home *** CD-ROM | disk | FTP | other *** search
/ Scene Storm / Scene Storm - Volume 1.iso / coding / c / snoopdos_source / subwin.c < prev    next >
C/C++ Source or Header  |  1996-02-16  |  107KB  |  3,853 lines

  1. /*
  2.  *        SUBWIN.C                                            vi:ts=4
  3.  *
  4.  *      Copyright (c) Eddy Carroll, September 1994.
  5.  *
  6.  *        This module handles all the windows other than the main window.
  7.  *        That is, the functions window, settings window and format
  8.  *        window.
  9.  */        
  10.  
  11. #include "system.h"
  12. #include "snoopdos.h"
  13. #include "gui.h"
  14.  
  15. #if 0
  16. #define DB(s)    KPrintF(s)
  17. #else
  18. #define DB(s)
  19. #endif
  20.  
  21. /*
  22.  *        These are used by all the requesters to decide what options to do
  23.  *        when leaving a requester (make current settings permanent or
  24.  *        restore the old settings)
  25.  */
  26. #define SEL_NONE          0        /* User didn't select an option yet        */
  27. #define SEL_USE            1        /* User selected USE in a requester        */
  28. #define SEL_CANCEL        2        /* User selected CANCEL in a requester    */
  29.  
  30. /*
  31.  *        These control which items are displayed in the System and DOS
  32.  *        columns in the function window.
  33.  */
  34. #define COL_SELECTED    0        /* Column shows selected items            */
  35. #define COL_ALL            1        /* Column shows all items                */
  36. #define COL_NONE        2        /* Column shows no items                */
  37.  
  38. #define SETBUTTON_FILE    0        /* Little image of a file folder        */
  39. #define SETBUTTON_FONT    1        /* Little image of a font folder        */
  40. #define SETBUTTON_MAX    2        /* Anything above this is a string ID    */
  41.  
  42. /*
  43.  *        These two are imported from SNOOPDOS.C
  44.  */
  45. extern char    SnoopDosTitle[];
  46.  
  47. /*
  48.  *        Variables for the format editor
  49.  */
  50. int FBoxA_Left;                /* X pos of left box in format window    */
  51. int FBoxA_Top;                /* Y pos of left box in format window    */
  52. int FBoxA_Width;            /* Width of left box in format window    */
  53. int FBoxA_Height;            /* Height of left box in format window    */
  54. int FBoxA_NumChars;            /* No. of characters across left box    */
  55. int FBoxA_CurLines;            /* No. of lines currently in left box    */
  56.  
  57. int FBoxB_Left;                /* X pos of right box in format window    */
  58. int FBoxB_Top;                /* Y pos of right box in format window    */
  59. int FBoxB_Width;            /* Hidth of right box in format window    */
  60. int FBoxB_Height;            /* Weight of right box in format window    */
  61. int FBoxB_NumChars;            /* No. of characters across right box    */
  62. int FBoxB_CurLines;            /* No. of lines currently in right box    */
  63.  
  64. int FBoxSpacing;            /* Distance between box text baselines    */
  65. int FBoxSelected;            /* Line number of right box selection    */
  66.                             /* (or FBOX_NOSELECT / FBOX_SELECTLEFT) */
  67.  
  68. int FBoxDeltaX;                /* Offset from mouse to corner of drag    */
  69. int FBoxDeltaY;                /* Offset from mouse to corner of drag    */
  70. int FBoxDragSelect;            /* Currently selected drag drop area    */
  71. int FormatCurLMB;            /* Current state of left mouse button    */
  72. int FormatMovingField;        /* If true, currently dragging field    */
  73. int FormatDragBox;            /* Box we're dragging from                */
  74. int FormatDragLine;            /* Line we're dragging from                */
  75.  
  76. char FBoxA_FormString[20];    /* sprintf format string for left box    */
  77. char FBoxB_FormString[20];    /* sprintf format string for right box    */
  78.  
  79. char FormatSaveFormat[MAX_FORM_LEN];    /* Save area for format ed    */
  80.  
  81. /*
  82.  *        These next two arrays are indices into the FieldTypes[] array
  83.  *        of format initialisers.
  84.  */
  85. typedef struct {
  86.     int    type;                            /* Type of this entry        */
  87.     int width;                            /* Width of this entry        */
  88. } EditEvent;
  89.     
  90. extern FieldInit FieldTypes[];            /* Pulled in from BUFFER.C    */
  91.  
  92. EditEvent CurrentFields[EF_COUNT+1];    /* Fields in current format    */
  93. EditEvent AvailableFields[EF_COUNT+1];    /* Fields still available    */
  94.  
  95. Settings            SavedFuncSets;        /* Saved function settings    */
  96. Settings            SavedSetupSets;        /* Saved setup settings        */
  97.  
  98. struct Gadget        *SetGadList;        /* Settings window gadgets    */
  99. struct Gadget        *FuncGadList;        /* Function window gadgets    */
  100. struct Gadget        *FormGadList;        /* Format window gadgets    */
  101. struct Image        *FileButtonImage;    /* Image of a file button    */
  102. struct Image        *FontButtonImage;    /* Image of a font button    */
  103.  
  104. struct TextFont        *FormBufFont;        /* Format window listview    */
  105. struct TextFont        *FormGadFont;        /* Format window gadgets    */
  106.  
  107. /*
  108.  *        We don't usually free the Function window gadgets when we close
  109.  *        the window (since it takes a long time to generate them). However,
  110.  *        if we change window font, then we need a way to be able to change
  111.  *        them. This variable shows you how.
  112.  */
  113. int        FuncSystemCol;        /* Mode of system column (all/none/sel)    */
  114. int        FuncDOSCol;            /* Mode of DOS column (all/none/select)    */
  115.  
  116. UBYTE    SavedCols[GID_NUMFUNCSETS];    /* Currently selected settings    */
  117. UBYTE    TempCols[GID_NUMFUNCSETS];    /* Currently selected settings    */
  118.  
  119. UBYTE    SetKeyboard[KB_SHORTCUT_SIZE];    /* For keyboard equivs        */
  120. UBYTE    FuncKeyboard[KB_SHORTCUT_SIZE];    /* For keyboard equivs        */
  121. UBYTE    FormKeyboard[KB_SHORTCUT_SIZE];    /* For keyboard equivs        */
  122.  
  123. /*
  124.  *        Now our font structures.
  125.  *
  126.  *        We do everything in terms of FontAttr structures, and whenever a
  127.  *        window needs a font, it OpenFont's it itself. This has several
  128.  *        advantages: it allows each window to dynamically select the
  129.  *        best-fitting font, and it also ensures no problems if we have a
  130.  *        window open with one font and the user than changes the font
  131.  *        to something else -- the first window will still have a valid
  132.  *        lock on the old font.
  133.  */
  134. extern struct TextAttr TopazFontAttr;
  135. extern struct TextAttr SystemFontAttr;
  136. extern struct TextAttr WindowFontAttr;
  137. extern struct TextAttr BufferFontAttr;
  138.  
  139. extern struct {
  140.     struct TextAttr *gadgetfa;
  141.     struct TextAttr *bufferfa;
  142. } MainWindowFontList[];                /* Imported from MAINWIN.C */
  143.  
  144. struct TextAttr *SubWindowFontList[] = {
  145.     &WindowFontAttr,
  146.     &SystemFontAttr,
  147.     &TopazFontAttr,
  148.     NULL
  149. };
  150.  
  151. /*
  152.  *        Next, all our gadget structures -- these are used to build the
  153.  *        font-sensitive gadget windows at runtime.
  154.  */
  155. struct FuncGadgets {
  156.     ULONG    gadgid;            /* Gadget ID                    */
  157.     UWORD    stringid;        /* Name of checkmark gadget     */
  158.     UBYTE    col;            /* Column (0, 1 or 2)            */
  159.     UBYTE    row;            /* Row (0 -- 13)                */
  160. };
  161.  
  162. struct FuncGadgets FuncGadgs[] = {
  163.     /*
  164.      *        General controls
  165.      */
  166.     GID_ONLYFAILS,        MSG_SHOWFAILS_GAD,        0, 0,
  167.     GID_SHOWCLINUM,        MSG_SHOWCLI_GAD,        0, 1,
  168.     GID_SHOWPATHS,        MSG_SHOWFULLPATHS_GAD,    0, 2,
  169.     GID_USEDEVNAMES,    MSG_USEDEVNAMES_GAD,    0, 3,
  170.     GID_MONPACKETS,        MSG_MONPACKETS_GAD,        0, 4,
  171.     GID_MONALLPACKETS,    MSG_MONALLPACKETS_GAD,    0, 5,
  172.     GID_MONROMCALLS,    MSG_MONROMCALLS_GAD,    0, 6,
  173.     GID_IGNOREWB,        MSG_IGNOREWB_GAD,        0, 7,
  174.     /*
  175.      *        System functions
  176.      */
  177.     GID_FINDPORT,        MSG_FINDPORT_GAD,        1, 0,
  178.     GID_FINDRESIDENT,    MSG_FINDRESIDENT_GAD,    1, 1,
  179.     GID_FINDSEMAPHORE,    MSG_FINDSEMAPHORE_GAD,    1, 2,
  180.     GID_FINDTASK,        MSG_FINDTASK_GAD,        1, 3,
  181.     GID_LOCKSCREEN,        MSG_LOCKSCREEN_GAD,        1, 4,
  182.     GID_OPENDEVICE,        MSG_OPENDEVICE_GAD,        1, 5,
  183.     GID_OPENFONT,        MSG_OPENFONT_GAD,        1, 6,
  184.     GID_OPENLIBRARY,    MSG_OPENLIBRARY_GAD,    1, 7,
  185.     GID_OPENRESOURCE,    MSG_OPENRESOURCE_GAD,    1, 8,
  186.     GID_READTOOLTYPES,    MSG_READTOOLTYPES_GAD,    1, 9,
  187.     GID_SENDREXX,        MSG_SENDREXX_GAD,        1, 10,
  188.  
  189.     /*
  190.      *        AmigaDOS Functions
  191.      */
  192.     GID_CHANGEDIR,        MSG_CHANGEDIR_GAD,        2, 0,
  193.     GID_DELETE,            MSG_DELETE_GAD,            2, 1,
  194.     GID_EXECUTE,        MSG_EXECUTE_GAD,        2, 2,
  195.     GID_GETVAR,            MSG_GETVAR_GAD,            2, 3,
  196.     GID_LOADSEG,        MSG_LOADSEG_GAD,        2, 4,
  197.     GID_LOCKFILE,        MSG_LOCKFILE_GAD,        2, 5,
  198.     GID_MAKEDIR,        MSG_MAKEDIR_GAD,        2, 6,
  199.     GID_MAKELINK,        MSG_MAKELINK_GAD,        2, 7,
  200.     GID_OPENFILE,        MSG_OPENFILE_GAD,        2, 8,
  201.     GID_RENAME,            MSG_RENAME_GAD,            2, 9,
  202.     GID_RUNCOMMAND,        MSG_RUNCOMMAND_GAD,        2, 10,
  203.     GID_SETVAR,            MSG_SETVAR_GAD,            2, 11,
  204.     GID_SYSTEM,            MSG_SYSTEM_GAD,            2, 12,
  205.  
  206.     0,                    0,                        0, 0
  207. };
  208.  
  209. /*
  210.  *        This structure defines the gadgets in the settings window. There
  211.  *        are three basic types of gadgets supported: cycle, string and
  212.  *        display. For cycle gadgets, data1 is the index of the current
  213.  *        selection, data2 is a 0-terminated array of message IDs that
  214.  *        will hold the possible ListView choices, and data3 is a pointer
  215.  *        to an array of string pointers of the same size (including
  216.  *        terminating NULL) that will be filled in by the code with actual
  217.  *        pointers to those strings.
  218.  *        
  219.  *        For string and display gadgets, data2 is a pointer to the string
  220.  *        to be displayed inside the gadget and data1/data3 are unused.
  221.  *        However, if promptid is specified, then data1 is the message
  222.  *        number of the prompt to be used in the button instead of defaulting
  223.  *        to a question mark (the width is automatically adjusted).
  224.  */        
  225. struct SetGadgets {
  226.     UWORD    gadgid;            /* Gadget ID                                */
  227.     UWORD    stringid;        /* ID of label name                         */
  228.     ULONG    gtype;            /* Gadget type (cycle, string, or display)    */
  229.     UWORD    promptid;        /* If non-zero, ID of optional "?" button      */
  230.     ULONG    data1;            /* See above                                */
  231.     void    *data2;            /* See above                                */
  232.     void    *data3;            /* See above                                */
  233.     UBYTE    col;            /* Start col (0 or 1)                        */
  234.     UBYTE    cwidth;            /* Column width (0, 1 or 2)                    */
  235.     UBYTE    row;            /* Row (0 to 6)                                */
  236. };
  237.  
  238. int SetCylHide[] = {
  239.     MSG_CYL_HIDE_GAD, MSG_CYL_ICONIFY_GAD, MSG_CYL_TOOLSMENU_GAD,
  240.     MSG_CYL_NONE_GAD, 0
  241. };
  242.  
  243. int SetCylOpenOn[] = {
  244.     MSG_CYL_DEFSCREEN_GAD, MSG_CYL_FRONTSCREEN_GAD, MSG_CYL_NAMEDSCREEN_GAD, 0
  245. };
  246.  
  247. int SetCylLogMode[] = {
  248.     MSG_CYL_PROMPT_USER_GAD, MSG_CYL_APPEND_GAD, MSG_CYL_OVERWRITE_GAD,
  249.     MSG_CYL_SERIALPORT_GAD, 0
  250. };
  251.  
  252. int SetCylFileIO[] = {
  253.     MSG_CYL_AUTOMATIC_GAD, MSG_CYL_IMMEDIATE_GAD, MSG_CYL_BUFFERED_GAD, 0
  254. };
  255.  
  256. char *SetCylHideText[HIDE_MAX+1];
  257. char *SetCylOpenOnText[SCREEN_MAX+1];
  258. char *SetCylLogModeText[LOGMODE_MAX+1];
  259. char *SetCylFileIOText[FILE_MAX+1];
  260.  
  261.  
  262. /*
  263.  *        If you re-arrange the order of these gadget definitions,
  264.  *        make sure you re-order the enum's that follow below as well.
  265.  */
  266. struct SetGadgets SetGadgs[] = {
  267.     GID_BUFFORMAT,    MSG_BUFFORMAT_GAD,    STRING_KIND,    GID_FORMATEDIT,    
  268.                                                         MSG_FORMATEDIT_GAD,
  269.                     NULL,                0,                    0,    2,    5,
  270.  
  271.     GID_LOGFORMAT,    MSG_LOGFORMAT_GAD,    STRING_KIND,    GID_FORMATCOPY,
  272.                                                         MSG_FORMATCOPYF_GAD,
  273.                     NULL,                0,                    0,    2,    6,
  274.     
  275.     GID_HIDEMETHOD,    MSG_HIDEMETHOD_GAD,    CYCLE_KIND,        0,    0,
  276.                     SetCylHide,            SetCylHideText,         0,    0,    0,
  277.     
  278.     GID_OPENON,        MSG_OPENON_GAD,        CYCLE_KIND,        0,    0,
  279.                     SetCylOpenOn,        SetCylOpenOnText,    0,    0,    1,
  280.  
  281.     GID_LOGMODE,    MSG_LOGMODE_GAD,    CYCLE_KIND,        0,    0,
  282.                     SetCylLogMode,        SetCylLogModeText,    0,    0,    2,
  283.  
  284.     GID_FILEIO,        MSG_FILEIO_GAD,        CYCLE_KIND,        0,    0,
  285.                     SetCylFileIO,        SetCylFileIOText,    0,    0,    3,
  286.     
  287.     GID_HOTKEY,        MSG_HOTKEY_GAD,        STRING_KIND,    0,    0,
  288.                     NULL,                0,                    1,    1,    0,
  289.     
  290.     GID_SCREENNAME,    MSG_SCREENNAME_GAD,    STRING_KIND,    0,    0,
  291.                     NULL,                0,                    1,    1,    1,
  292.     
  293.     GID_LOGFILE,    MSG_LOGFILE_GAD,    STRING_KIND,    GID_FILEPROMPT,
  294.                                                         SETBUTTON_FILE,
  295.                     NULL,                0,                    1,    1,    2,
  296.  
  297.     GID_WINDOWFONT,    MSG_WINDOWFONT_GAD,    TEXT_KIND,        GID_WFONTPROMPT,
  298.                                                         SETBUTTON_FONT,
  299.                     NULL,                0,                    1,    1,    3,
  300.     
  301.     GID_BUFFERFONT,    MSG_BUFFERFONT_GAD,    TEXT_KIND,        GID_BFONTPROMPT,
  302.                                                         SETBUTTON_FONT,
  303.                     NULL,                0,                    1,    1,    4,
  304.  
  305.     0
  306. };
  307.  
  308. /*
  309.  *        The following gadgets should match the _order_ that the above
  310.  *        gadgets are laid out in, since they are used as indices into the
  311.  *        above array.
  312.  */
  313. typedef enum {
  314.     SG_BufferFormat,
  315.     SG_LogfileFormat,
  316.     SG_HideMethod,
  317.     SG_ScreenType,
  318.     SG_LogMode,
  319.     SG_FileIOType,
  320.     SG_HotKey,
  321.     SG_ScreenName,
  322.     SG_LogFile,
  323.     SG_WindowFont,
  324.     SG_BufferFont,
  325. } SetGadgetEnums;
  326.  
  327. /*
  328.  *        Arrays of gadget names for calculating minimum width
  329.  */
  330.  
  331. /*
  332.  *        Miscellaneous gadgets in functions window
  333.  */
  334. int MiscColNames[] = {
  335.     MSG_SHOWFAILS_GAD,
  336.     MSG_SHOWCLI_GAD,
  337.     MSG_SHOWFULLPATHS_GAD,
  338.     MSG_USEDEVNAMES_GAD,
  339.     MSG_MONPACKETS_GAD,
  340.     MSG_MONALLPACKETS_GAD,
  341.     MSG_IGNOREWB_GAD,
  342.     0
  343. };
  344.  
  345. /*
  346.  *        System gadgets in functions window
  347.  */
  348. int SysColNames[] = {
  349.     MSG_FINDPORT_GAD,     
  350.     MSG_FINDRESIDENT_GAD, 
  351.     MSG_FINDSEMAPHORE_GAD,
  352.     MSG_FINDTASK_GAD,     
  353.     MSG_LOCKSCREEN_GAD,   
  354.     MSG_OPENDEVICE_GAD,   
  355.     MSG_OPENFONT_GAD,     
  356.     MSG_OPENLIBRARY_GAD,  
  357.     MSG_OPENRESOURCE_GAD, 
  358.     MSG_READTOOLTYPES_GAD,
  359.     MSG_SENDREXX_GAD, 
  360.     0
  361. };
  362.  
  363. /*
  364.  *        AmigaDOS gadgets in functions window
  365.  */
  366. int DOSColNames[] = {
  367.     MSG_CHANGEDIR_GAD, 
  368.     MSG_DELETE_GAD,    
  369.     MSG_EXECUTE_GAD,   
  370.     MSG_GETVAR_GAD,    
  371.     MSG_LOADSEG_GAD,   
  372.     MSG_LOCKFILE_GAD,  
  373.     MSG_MAKEDIR_GAD,   
  374.     MSG_MAKELINK_GAD,  
  375.     MSG_OPENFILE_GAD,  
  376.     MSG_RENAME_GAD,    
  377.     MSG_RUNCOMMAND_GAD,
  378.     MSG_SETVAR_GAD,    
  379.     MSG_SYSTEM_GAD,
  380.     0
  381. };
  382.  
  383. /*
  384.  *        Aditional gadgets in function window
  385.  */
  386. int FuncCycleText[]        = { MSG_ALL_GAD, MSG_NONE_GAD, MSG_SELECTED_GAD, 0 };
  387. int FuncCycleName[]        = { MSG_SELSYSTEM_GAD, MSG_SELDOS_GAD, 0 };
  388. int UseCancelUndoText[] = { MSG_USE_GAD, MSG_CANCEL_GAD, MSG_UNDO_GAD, 0 };
  389.  
  390. /*
  391.  *        Left column gadgets names in settings window
  392.  */
  393. int SettingsLeftNames[] = {
  394.     MSG_HIDEMETHOD_GAD,
  395.     MSG_OPENON_GAD,
  396.     MSG_LOGMODE_GAD,
  397.     MSG_FILEIO_GAD,
  398.     MSG_BUFFORMAT_GAD,
  399.     MSG_LOGFORMAT_GAD,
  400.     0
  401. };
  402.  
  403. /*
  404.  *        Right column gadget names in settings window
  405.  */
  406. int SettingsRightNames[] = {
  407.     MSG_HOTKEY_GAD,
  408.     MSG_SCREENNAME_GAD,
  409.     MSG_LOGFILE_GAD,
  410.     MSG_WINDOWFONT_GAD,
  411.     MSG_BUFFERFONT_GAD,
  412.     0
  413. };
  414.  
  415. /*
  416.  *        Two mini buttons attached to format gadgets in settings window
  417.  *        Note that we have two types of possibility: one for fixed point
  418.  *        fonts and one for proportional fonts. This is so that we can
  419.  *        arrange for the two strings "Edit..." and "Copy" to always
  420.  *        look properly aligned, regardless of font type. If we didn't do
  421.  *        this, then with fixed point fonts, "Copy" looks mis-aligned
  422.  *        with respect to "Edit..." because they are different lengths.
  423.  */
  424. int SetMiniButtonsP[] = {
  425.     MSG_FORMATCOPYP_GAD,
  426.     MSG_FORMATEDIT_GAD,
  427.     0
  428. };
  429.  
  430. int SetMiniButtonsF[] = {
  431.     MSG_FORMATCOPYF_GAD,
  432.     MSG_FORMATEDIT_GAD,
  433.     0
  434. };
  435.  
  436. /*
  437.  *        Left column gadget contents in settings
  438.  */
  439. int SettingsLeftContents[] = {
  440.     MSG_CYL_HIDE_GAD,
  441.     MSG_CYL_ICONIFY_GAD,
  442.     MSG_CYL_TOOLSMENU_GAD,
  443.     MSG_CYL_DEFSCREEN_GAD,
  444.     MSG_CYL_FRONTSCREEN_GAD,
  445.     MSG_CYL_NAMEDSCREEN_GAD,
  446.     MSG_CYL_PROMPT_USER_GAD,
  447.     MSG_CYL_APPEND_GAD,
  448.     MSG_CYL_OVERWRITE_GAD,
  449.     MSG_CYL_AUTOMATIC_GAD,
  450.     MSG_CYL_IMMEDIATE_GAD,
  451.     MSG_CYL_BUFFERED_GAD,
  452.     0
  453. };
  454.  
  455. /*
  456.  *        Mega struct that collects all the data needed to create useful BOBs.
  457.  */
  458. typedef struct MyGel {
  459.     struct GelsInfo  gelinfo;            /* GelInfo for entire structure    */
  460.     WORD             nextline[8];        /* Nextline data                */ 
  461.     WORD             *lastcolor[8];        /* Last colour data                */
  462.     struct RastPort     *mainrast;            /* Rastport bob is displayed in    */
  463.     struct collTable colltable;            /* Collision table                */
  464.     struct VSprite     vshead;            /* Head sprite anchor            */
  465.     struct VSprite     vstail;            /* Tail sprite anchor            */
  466.     struct VSprite     bobvsprite;        /* Vsprite used for bob            */
  467.     struct Bob         bob;                /* Data for a single bob        */
  468.     struct RastPort  rastport;            /* Rastport for our BOB            */
  469.     struct BitMap     bitmap;            /* Bitmap for our BOB            */
  470.     ULONG             planesize;            /* Size of one plane in bob        */
  471.     UBYTE            *planedata;            /* Pointer to first plane        */
  472.     UBYTE             *chipdata;            /* Pointer to all CHIP RAM data    */
  473.     ULONG             chipsize;            /* Total size of allocated CHIP    */
  474. } MyGel;
  475.  
  476. MyGel    *TextBob;                        /* Info about GEL/BOBs            */
  477.  
  478. /*
  479.  *        Some prototypes private to this file
  480.  */
  481. MyGel *CreateBob(struct RastPort *rport, int width, int height, int transp);
  482. void FreeBob(MyGel *mygel);
  483. void UpdateBob(int x, int y);
  484. int  PickupBob(int hit, int x, int y);
  485. void DropBob();
  486.  
  487. /*****************************************************************************
  488.  *
  489.  *        Start of functions!
  490.  *
  491.  *****************************************************************************/
  492.  
  493. /*
  494.  *        CleanupSubWindows()
  495.  *
  496.  *        Frees any resources associated with this module
  497.  */
  498. void CleanupSubWindows(void)
  499. {
  500.     PurgeFuncGadgets = 1;
  501.     CloseFunctionWindow();
  502.     CloseSettingsWindow();
  503.     CloseFormatWindow();
  504. }
  505.  
  506. /*
  507.  *        GetFuncName(gadgetid)
  508.  *
  509.  *        Returns a pointer to a string describing the function name which
  510.  *        matches the gadget ID passed in. This is used by PATCHES.C when
  511.  *        it is unpatching the patched functions at exit time to identify
  512.  *        which function can't be unpatched in the event of a problem.
  513.  */
  514. char *GetFuncName(int gadgetid)
  515. {
  516.     struct FuncGadgets *fg = FuncGadgs;
  517.  
  518.     if (gadgetid == GID_SENDREXX)    /* Special-case this multi-function one */
  519.         return MSG(MSG_PACKET_NAME);
  520.  
  521.     for (fg = &FuncGadgs[0]; fg->gadgid; fg++) {
  522.         if (fg->gadgid == gadgetid)
  523.             return MSG(fg->stringid);
  524.     }
  525.     return ("<Unknown Function>");
  526. }
  527.  
  528. /*
  529.  *        CreateFunctionGadgets(fontattr, getsize, &width, &height)
  530.  *
  531.  *        Creates all the gadgets for the function window. If getsize
  532.  *        is true, then the width and height values are filled in with
  533.  *        the dimensions of the window needed to hold the gadgets. In
  534.  *        this case, NULL is returned if the window would be too big to
  535.  *        fit on the current screen, or non-NULL if width and height
  536.  *        were successfully initialised.
  537.  *
  538.  *        If getsize is zero, then the actual gadgets are created and
  539.  *        a pointer to the gadget list is returned, or NULL if an
  540.  *        error occurred (typically, out of memory).
  541.  */
  542. struct Gadget *CreateFunctionGadgets(struct TextAttr *fontattr,
  543.                                      int getsize, int *pwidth, int *pheight)
  544. {
  545.     static char *cyltext[4];
  546.     struct TextFont *font;
  547.     struct FuncGadgets *fg;
  548.     struct NewGadget ng;
  549.     struct Gadget *gadlist;
  550.     struct Gadget *gad;
  551.     UWORD spacing[3];
  552.     UWORD yoffset[3]; 
  553.     UWORD colpos[3];
  554.     int heightadjust = 0;
  555.     int width;
  556.     int height;
  557.     int gwidth;
  558.     int gheight;
  559.     int fonty;
  560.     int colspace = 30;
  561.     int topline;
  562.     int w1, w2;
  563.  
  564.     if (!FuncVI) {
  565.         FuncVI = GetVisualInfoA(SnoopScreen, NULL);
  566.         if (!FuncVI)
  567.             return (NULL);
  568.     }
  569.     font = MyOpenFont(fontattr);
  570.     if (!font)
  571.         return (NULL);
  572.  
  573.     fonty        = font->tf_YSize;
  574.     gheight        = fonty   + 3;
  575.     gwidth         = gheight + 15;
  576.     
  577.     spacing[0]  = fonty + 4;
  578.     spacing[1]  = fonty + 4;
  579.     spacing[2]  = fonty + 4;
  580.     yoffset[1]    = TitlebarHeight + fonty/2;
  581.     yoffset[2]    = yoffset[1];
  582.     yoffset[0]    = yoffset[1] + 10 * spacing[1] - 7 * spacing[0];
  583.  
  584.     colpos[0]    = BorderLeft + FUNC_MARGIN;
  585.     colpos[1]    = colpos[0]  + MaxTextLen(font, MiscColNames)
  586.                   + gwidth + colspace;
  587.     w1            = MaxTextLen(font, SysColNames) + gwidth;
  588.     w2            = GetTextLen(font, MSG(MSG_SYSFUNCS_GAD));
  589.     colpos[2]    = colpos[1]  + MAX(w1, w2) + colspace;
  590.     w1            = MaxTextLen(font, DOSColNames) + gwidth;
  591.     w2            = GetTextLen(font, MSG(MSG_DOSFUNCS_GAD));
  592.     width        = colpos[2]  + MAX(w1, w2) + FUNC_MARGIN + BorderRight + 8;
  593.     height      = yoffset[2] + spacing[2] * 15 + BorderBottom;
  594.  
  595.     topline = yoffset[2];
  596.     if (ScreenHeight < 256 && height > ScreenHeight) {
  597.         /*
  598.          *        For medium and low resolution screens, shave another
  599.          *        few pixels from the height. Our aim is to be able to
  600.          *        open on a 640 x 200 screen with a 15 point screen font.
  601.          */
  602.         heightadjust = -2;
  603.         height      += heightadjust * 2;
  604.     }
  605.     if ((height + spacing[2] * 2) <= ScreenHeight) {
  606.         int disp = (spacing[2] * 3) / 2;
  607.  
  608.         yoffset[0] += disp;
  609.         yoffset[1] += disp;
  610.         yoffset[2] += disp;
  611.         height     += disp;
  612.     }
  613.  
  614.     if (width > ScreenWidth || height > ScreenHeight) {
  615.         CloseFont(font);
  616.         return (NULL);
  617.     }
  618.     if (getsize) {
  619.         CloseFont(font);
  620.         *pwidth  = width;
  621.         *pheight = height;
  622.         return (struct Gadget *)(-1);
  623.     }
  624.  
  625.     /*
  626.      *        Now create our new gadgets
  627.      */    
  628.     ng.ng_Height        = gheight; 
  629.     ng.ng_Width            = gwidth;  
  630.     ng.ng_TextAttr        = fontattr;
  631.     ng.ng_VisualInfo    = FuncVI;
  632.     ng.ng_Flags         = PLACETEXT_RIGHT;
  633.  
  634.     gadlist = NULL;
  635.     gad = CreateContext(&gadlist);
  636.     if (!gad)
  637.         goto fgad_failed;
  638.  
  639.     for (fg = &FuncGadgs[0]; fg->gadgid; fg++) {
  640.         int col = fg->col;
  641.  
  642.         ng.ng_LeftEdge      = colpos[col];
  643.         ng.ng_TopEdge       = fg->row * spacing[col] + yoffset[col];
  644.         ng.ng_GadgetText    = MSG(fg->stringid);
  645.         ng.ng_GadgetID        = fg->gadgid;
  646.  
  647.         gad = CreateGadget(CHECKBOX_KIND, gad, &ng,
  648.                            GT_Underscore,    '_',
  649.                            GTCB_Scaled,     TRUE,
  650.                            TAG_DONE);
  651.         if (!gad)
  652.             goto fgad_failed;
  653.         Gadget[fg->gadgid] = gad;
  654.         AddKeyShortcut(FuncKeyboard, fg->gadgid, fg->stringid);
  655.     }
  656.  
  657.     /*
  658.      *        Now create the remaining window gadgets
  659.      */
  660.     ng.ng_LeftEdge         = colpos[0]
  661.                           + GetTextLen(font, MSG(MSG_MATCHNAME_GAD)) + 10;
  662.     ng.ng_TopEdge          = yoffset[1] + (23 * spacing[1]) / 2;
  663.     ng.ng_GadgetText    = MSG(MSG_MATCHNAME_GAD);
  664.     ng.ng_GadgetID        = GID_MATCHNAME;
  665.     ng.ng_Width         = colpos[2] - ng.ng_LeftEdge - colspace + 8;
  666.     ng.ng_Height        = gheight + 3;
  667.     ng.ng_Flags         = PLACETEXT_LEFT;
  668.  
  669.     gad = CreateGadget(STRING_KIND,        gad, &ng,
  670.                        GT_Underscore,    '_',
  671.                        GTST_MaxChars,    MAX_STR_LEN,
  672.                        GTST_String,         CurSettings.Func.Pattern,
  673.                        TAG_DONE);
  674.     if (!gad)
  675.         goto fgad_failed;
  676.     Gadget[GID_MATCHNAME] = gad;
  677.     AddKeyShortcut(FuncKeyboard, GID_MATCHNAME, MSG_MATCHNAME_GAD);
  678.  
  679.     ng.ng_GadgetText    = MSG(MSG_SELSYSTEM_GAD);
  680.     ng.ng_GadgetID        = GID_SELSYSTEM;
  681.     ng.ng_Height        = gheight + 3;
  682.     ng.ng_Width            = MaxTextLen(font, FuncCycleText) + 40;
  683.     ng.ng_LeftEdge        = colpos[0] + MaxTextLen(font, FuncCycleName) + 10;
  684.     ng.ng_TopEdge        = yoffset[1];
  685.     cyltext[0]            = MSG(MSG_SELECTED_GAD);
  686.     cyltext[1]            = MSG(MSG_ALL_GAD);
  687.     cyltext[2]            = MSG(MSG_NONE_GAD);
  688.     cyltext[3]            = NULL;
  689.  
  690.     gad = CreateGadget(CYCLE_KIND,        gad, &ng,
  691.                        GT_Underscore,    '_',
  692.                        GTCY_Labels,        cyltext,
  693.                        GTCY_Active,        COL_SELECTED,
  694.                        TAG_DONE);
  695.     if (!gad)
  696.         goto fgad_failed;
  697.     Gadget[GID_SELSYSTEM] = gad;
  698.     AddKeyShortcut(FuncKeyboard, GID_SELSYSTEM, MSG_SELSYSTEM_GAD);
  699.  
  700.     ng.ng_GadgetText    = MSG(MSG_SELDOS_GAD);
  701.     ng.ng_GadgetID        = GID_SELDOS;
  702.     ng.ng_TopEdge        = (yoffset[0] + yoffset[1]) / 2;
  703.  
  704.     gad = CreateGadget(CYCLE_KIND,        gad, &ng,
  705.                        GT_Underscore,    '_',
  706.                        GTCY_Labels,        cyltext,
  707.                        GTCY_Active,        COL_SELECTED,
  708.                        TAG_DONE);
  709.     if (!gad)
  710.         goto fgad_failed;
  711.     Gadget[GID_SELDOS] = gad;
  712.     AddKeyShortcut(FuncKeyboard, GID_SELDOS, MSG_SELDOS_GAD);
  713.  
  714.     ng.ng_Width            = MaxTextLen(font, UseCancelUndoText) + 32;
  715.     ng.ng_Height        = fonty + GadgetHeight;
  716.     ng.ng_GadgetText    = MSG(MSG_USE_GAD);
  717.     ng.ng_GadgetID        = GID_FUNCUSE;
  718.     ng.ng_LeftEdge        = colpos[0];
  719.     ng.ng_TopEdge        = yoffset[2] + heightadjust + (27 * spacing[2]) / 2;
  720.     ng.ng_Flags            = PLACETEXT_IN;
  721.  
  722.     gad = CreateGadget(BUTTON_KIND,        gad, &ng,
  723.                        GT_Underscore,    '_',
  724.                        TAG_DONE);
  725.     if (!gad)
  726.         goto fgad_failed;
  727.     Gadget[GID_FUNCUSE] = gad;
  728.     AddKeyShortcut(FuncKeyboard, GID_FUNCUSE, MSG_USE_GAD);
  729.     
  730.     ng.ng_LeftEdge        = width - BorderRight - FUNC_MARGIN - ng.ng_Width;
  731.     ng.ng_GadgetText    = MSG(MSG_CANCEL_GAD);
  732.     ng.ng_GadgetID        = GID_FUNCCANCEL;
  733.  
  734.     gad = CreateGadget(BUTTON_KIND,        gad, &ng,
  735.                        GT_Underscore,    '_',
  736.                        TAG_DONE);
  737.     if (!gad)
  738.         goto fgad_failed;
  739.     Gadget[GID_FUNCCANCEL] = gad;
  740.     AddKeyShortcut(FuncKeyboard, GID_FUNCCANCEL, MSG_CANCEL_GAD);
  741.  
  742.     ng.ng_LeftEdge        = (ng.ng_LeftEdge + BorderLeft + FUNC_MARGIN) / 2;
  743.     ng.ng_GadgetText    = MSG(MSG_UNDO_GAD);
  744.     ng.ng_GadgetID        = GID_FUNCUNDO;
  745.  
  746.     gad = CreateGadget(BUTTON_KIND,        gad, &ng,
  747.                        GT_Underscore,    '_',
  748.                        TAG_DONE);
  749.     if (!gad)
  750.         goto fgad_failed;
  751.     Gadget[GID_FUNCUNDO] = gad;
  752.     AddKeyShortcut(FuncKeyboard, GID_FUNCUNDO, MSG_UNDO_GAD);
  753.     
  754.     if (topline != yoffset[2]) {
  755.         /*
  756.          *        If there's room at the top of the window, create two text
  757.          *        gadgets with the column headings for the System and DOS cols.
  758.          */
  759.         ng.ng_TopEdge        = topline;
  760.         ng.ng_LeftEdge        = colpos[1];
  761.         ng.ng_GadgetText    = "";
  762.         ng.ng_GadgetID        = 0;
  763.  
  764.         gad = CreateGadget(TEXT_KIND,    gad, &ng,
  765.                            GTTX_Text,    MSG(MSG_SYSFUNCS_GAD),
  766.                            TAG_DONE);
  767.         if (!gad)
  768.             goto fgad_failed;
  769.  
  770.         ng.ng_LeftEdge        = colpos[2];
  771.         gad = CreateGadget(TEXT_KIND,    gad, &ng,
  772.                            GTTX_Text,    MSG(MSG_DOSFUNCS_GAD),
  773.                            TAG_DONE);
  774.         if (!gad)
  775.             goto fgad_failed;
  776.     }
  777.     PurgeFuncGadgets = 0;    /* No need to purge now */
  778.     CloseFont(font);
  779.     return (gadlist);
  780.  
  781. fgad_failed:
  782.     if (gadlist)
  783.         FreeGadgets(gadlist);
  784.     CloseFont(font);
  785.     return (NULL);
  786. }
  787.  
  788. /*
  789.  *        OpenFunctionWindow()
  790.  *
  791.  *        Opens the functions window with all the functions gadgets.
  792.  *        Returns TRUE for success, FALSE for failure.
  793.  *        The window will contain all necessary gadgets.
  794.  *
  795.  *        As with the Settings window, we try a variety of fonts until we
  796.  *        find one that fits onto the screen.
  797.  */
  798. int OpenFunctionWindow(void)
  799. {
  800.     static struct TextAttr funcfontattr =
  801.         { "empty-storage-for-func-fonts...", 0, FS_NORMAL, FPB_DISKFONT};
  802.  
  803.     static int width;        /* Maintained from call to call */
  804.     static int height;
  805.  
  806.     int left = CurSettings.FuncWinLeft;
  807.     int top  = CurSettings.FuncWinTop;
  808.     struct TextAttr *fontattr = NULL;
  809.     struct Window *win;
  810.     int i;
  811.  
  812.     CheckSegTracker();
  813.     if (FuncWindow) {
  814.         WindowToFront(FuncWindow);
  815.         ActivateWindow(FuncWindow);
  816.         return (TRUE);
  817.     }
  818.     if (!CheckForScreen())
  819.         return (FALSE);
  820.  
  821.     SavedFuncSets = CurSettings;        /* Save so we can restore later */
  822.  
  823.     if (!FuncGadList) {
  824.         /*
  825.          *        Find out what dimensions our new window should be; to do
  826.          *        this, we calculate the size with a variety of fonts until
  827.          *        we find one that works.
  828.          */
  829.         int i;
  830.  
  831.         for (i = 0; fontattr = SubWindowFontList[i]; i++) {
  832.             if (CreateFunctionGadgets(fontattr, TRUE, &width, &height))
  833.                 break;
  834.         }
  835.         if (!fontattr) {
  836.             ShowError(MSG(MSG_ERROR_OPENFUNC));
  837.             return (FALSE);
  838.         }
  839.         /*
  840.          *        We need to make a copy of the fontattr now so that if
  841.          *        the user changes the font, all our gadgets don't suddenly
  842.          *        inherit the new font (at least until the window has been
  843.          *        closed and re-opened!)
  844.          */
  845.         strcpy(funcfontattr.ta_Name, fontattr->ta_Name);
  846.         funcfontattr.ta_YSize = fontattr->ta_YSize;
  847.         fontattr = &funcfontattr;
  848.     }
  849.     if (left == -1)  left = (ScreenWidth  - width)  / 2;
  850.     if (top  == -1)  top  = (ScreenHeight - height) / 2;
  851.  
  852.     win = OpenWindowTags(NULL,
  853.                          WA_Title,            MSG(MSG_FUNCTION_TITLE),
  854.                          WA_IDCMP,            IDCMP_CLOSEWINDOW     |
  855.                                              IDCMP_REFRESHWINDOW     |
  856.                                             IDCMP_NEWSIZE         |
  857.                                             IDCMP_INACTIVEWINDOW |
  858.                                             IDCMP_RAWKEY         |
  859.                                             BUTTONIDCMP,
  860.                          WA_Left,              left,
  861.                          WA_Top,              top,
  862.                          WA_Width,            width,
  863.                          WA_Height,            height,
  864.                          WA_Flags,            WFLG_DRAGBAR         |
  865.                                              WFLG_DEPTHGADGET     |
  866.                                             WFLG_ACTIVATE         |
  867.                                             WFLG_RMBTRAP         |
  868.                                             WFLG_NEWLOOKMENUS,
  869.                          RefreshTag,        TRUE,
  870.                          WA_NoCareRefresh,    NoCareRefreshBool,
  871.                          WA_PubScreen,        SnoopScreen,
  872.                          TAG_DONE);
  873.     if (!win) {
  874.         ShowError(MSG(MSG_ERROR_OPENFUNC));
  875.         return (FALSE);
  876.     }
  877.  
  878.     if (!FuncGadList) {
  879.         FuncGadList = CreateFunctionGadgets(fontattr, 0, 0, 0);
  880.         if (!FuncGadList) {
  881.             CloseWindow(win);
  882.             ShowError(MSG(MSG_ERROR_OPENFUNC));
  883.             return (FALSE);
  884.         }
  885.     }
  886.  
  887.     /*
  888.      *        Now update function gadgets to reflect current settings
  889.      *        for AmigaDOS functions. Under V39+, we can do this before
  890.      *        adding them to the window. Under V37, we have to do it
  891.      *        after adding them to the window.
  892.      */
  893.     if (GadToolsBase->lib_Version < 39) {
  894.         AddGList(win, FuncGadList, -1, -1, NULL);
  895.         RefreshGList(FuncGadList, win, NULL, -1);
  896.         GT_RefreshWindow(win, NULL);
  897.         for (i = FIRST_BOOL_GADGET; i <= LAST_BOOL_GADGET; i++) {
  898.             if (Gadget[i]) {
  899.                 GT_SetGadgetAttrs(Gadget[i], win, NULL,
  900.                                   GTCB_Checked, CurSettings.Func.Opts[i],
  901.                                   TAG_DONE);
  902.             }
  903.         }
  904.     } else { /* GadToolsBase->lib_Version >= 39 */
  905.         for (i = FIRST_BOOL_GADGET; i <= LAST_BOOL_GADGET; i++) {
  906.             if (Gadget[i]) {
  907.                 GT_SetGadgetAttrs(Gadget[i], NULL, NULL,
  908.                                   GTCB_Checked, CurSettings.Func.Opts[i],
  909.                                   TAG_DONE);
  910.             }
  911.         }
  912.         AddGList(win, FuncGadList, -1, -1, NULL);
  913.         RefreshGList(FuncGadList, win, NULL, -1);
  914.         GT_RefreshWindow(win, NULL);
  915.     }
  916.  
  917.     /*
  918.      *        All done, so initialise some globals and return
  919.      */
  920.     FuncWindow        = win;
  921.     FuncWindowPort    = win->UserPort;
  922.     FuncWindowMask    = 1 << FuncWindowPort->mp_SigBit;
  923.     FuncSystemCol   = COL_SELECTED;
  924.     FuncDOSCol        = COL_SELECTED;
  925.     if (DisableNestCount)
  926.         DisableWindow(FuncWindow, &FuncRequester);
  927.     return (TRUE);
  928. }
  929.  
  930. /*
  931.  *        CreateSettingsGadgets(fontattr, getsize, &pwidth, &pheight)
  932.  *
  933.  *        Creates the gadgets list for the settings window using the specified
  934.  *        window font. If the window would be to big for the current screen
  935.  *        using this font, or if there is a problem creating the gadgets,
  936.  *        returns NULL.
  937.  *
  938.  *        The returned gadget list should be passed to FreeGadgets() when
  939.  *        it is no longer required.
  940.  *
  941.  *        If getsize is true, then pwidth and pheight are filled in with the
  942.  *        dimensions of the window size needed to hold the gadgets, but
  943.  *        no actual gadget creation is carried out. In this case, NULL is
  944.  *        returned for a failure (couldn't open font, or window size would
  945.  *        exceed current screen size) and non-NULL for success.
  946.  */
  947. struct Gadget *CreateSettingsGadgets(struct TextAttr *fontattr,
  948.                                      int getsize, int *pwidth, int *pheight)
  949. {
  950.     struct SetGadgets *sg;
  951.     struct NewGadget ng;
  952.     struct NewGadget ngbut;
  953.     struct TextFont *font;
  954.     struct Gadget *gadlist;
  955.     struct Gadget *gad;
  956.     UWORD spacing;
  957.     UWORD yoffset;
  958.     UWORD colpos[2];
  959.     UWORD colwidth[3];
  960.     int miniwidth;
  961.     int width;
  962.     int height;
  963.     int gheight;
  964.     int fonty;
  965.     int fontx;
  966.  
  967.     if (!SetVI) {
  968.         SetVI = GetVisualInfoA(SnoopScreen, NULL);
  969.         if (!SetVI)
  970.             return (NULL);
  971.     }
  972.     font = MyOpenFont(fontattr);
  973.     if (!font)
  974.         return (NULL);
  975.     
  976.     fonty        = font->tf_YSize;
  977.     fontx        = font->tf_XSize;
  978.  
  979.     gheight        = fonty + GadgetHeight;
  980.     spacing     = fonty + GadgetSpacing;
  981.     yoffset        = TitlebarHeight + fonty/2;
  982.     colpos[0]    = BorderLeft + SET_MARGIN
  983.                   + MaxTextLen(font, SettingsLeftNames) + 7;
  984.     colwidth[0] = MaxTextLen(font, SettingsLeftContents) + 40;
  985.     colpos[1]    = colpos[0] + colwidth[0] + SET_MARGIN*2
  986.                               + MaxTextLen(font, SettingsRightNames);
  987.     colwidth[1] = fontx * 24; /* Room for about 24 chars in string gadgets */
  988.     colwidth[2] = colwidth[1] + colpos[1] - colpos[0];    /* Dual width */
  989.  
  990.     /*
  991.      *        See SetMiniButtons[] definitions for explanation of this bit
  992.      */
  993.     if (font->tf_Flags & FPF_PROPORTIONAL) {
  994.         miniwidth = MaxTextLen(font, SetMiniButtonsP) + 20;
  995.         SetGadgs[1].data1 = MSG_FORMATCOPYP_GAD;
  996.     } else {
  997.         miniwidth = MaxTextLen(font, SetMiniButtonsF) + 20;
  998.         SetGadgs[1].data1 = MSG_FORMATCOPYF_GAD;
  999.     }
  1000.  
  1001.     width        = colpos[1] + colwidth[1] + SET_MARGIN + BorderRight;
  1002.     height      = yoffset + spacing * 8 + BorderBottom;
  1003.  
  1004.     if (width > ScreenWidth || height >ScreenHeight) {
  1005.         CloseFont(font);
  1006.         return (NULL);
  1007.     }
  1008.     if (getsize) {
  1009.         *pwidth  = width;
  1010.         *pheight = height;
  1011.         CloseFont(font);
  1012.         return (struct Gadget *)(-1);
  1013.     }
  1014.  
  1015.     /*
  1016.      *        Okay, looks like our size is okay so now prime our gadget
  1017.      *        table with the current settings values to use when the
  1018.      *        gadget is created.
  1019.      *
  1020.      */
  1021. #define DEF_CYCLE(x)    SetGadgs[SG_##x].data1
  1022. #define DEF_STRING(x)    SetGadgs[SG_##x].data2
  1023.  
  1024.     DEF_CYCLE(HideMethod)      = CurSettings.Setup.HideMethod;
  1025.     DEF_CYCLE(ScreenType)      = CurSettings.Setup.ScreenType;
  1026.     DEF_CYCLE(LogMode)          = CurSettings.Setup.LogMode;
  1027.     DEF_CYCLE(FileIOType)      = CurSettings.Setup.FileIOType;
  1028.     DEF_STRING(HotKey)          = CurSettings.Setup.HotKey;
  1029.     DEF_STRING(ScreenName)      = CurSettings.Setup.ScreenName;
  1030.     DEF_STRING(LogFile)          = CurSettings.Setup.LogFile;
  1031.     DEF_STRING(WindowFont)      = GetFontDesc(WindowFontDesc,
  1032.                                             WindowFontName, WindowFontSize);
  1033.     DEF_STRING(BufferFont)      = GetFontDesc(BufferFontDesc,
  1034.                                              BufferFontName, BufferFontSize);
  1035.     DEF_STRING(BufferFormat)  = BufFormat;
  1036.     DEF_STRING(LogfileFormat) = LogFormat;
  1037.  
  1038.     /*
  1039.      *        Next, onto the gadget creation itself
  1040.      */
  1041.     ng.ng_Height        = gheight; 
  1042.     ng.ng_TextAttr        = fontattr;
  1043.     ng.ng_VisualInfo    = SetVI;
  1044.     ng.ng_Flags         = PLACETEXT_LEFT;
  1045.  
  1046.     ngbut.ng_Height        = gheight; 
  1047.     ngbut.ng_TextAttr    = fontattr;
  1048.     ngbut.ng_VisualInfo    = SetVI;
  1049.     ngbut.ng_Flags        = PLACETEXT_IN;
  1050.  
  1051.     FileButtonImage = CreateCustomImage(IMAGE_FILE, gheight+2-2*SquareAspect);
  1052.     FontButtonImage = CreateCustomImage(IMAGE_FONT, gheight);
  1053.     if (!FileButtonImage || !FontButtonImage) {
  1054.         CloseFont(font);
  1055.         return (NULL);
  1056.     }
  1057.     gadlist = NULL;
  1058.     gad = CreateContext(&gadlist);
  1059.     if (!gad) {
  1060.         CloseFont(font);
  1061.         return (NULL);
  1062.     }
  1063.  
  1064.     for (sg = &SetGadgs[0]; sg->gadgid; sg++) {
  1065.         ng.ng_LeftEdge      = colpos[sg->col];
  1066.         ng.ng_Width            = colwidth[sg->cwidth];
  1067.         ng.ng_TopEdge       = yoffset + sg->row * spacing;
  1068.         ng.ng_GadgetText    = MSG(sg->stringid);
  1069.         ng.ng_GadgetID        = sg->gadgid;
  1070.         ng.ng_Height        = gheight;
  1071.  
  1072.         if (sg->promptid) {
  1073.             /*
  1074.              *        Create optional mini gadget to right of main gadget.
  1075.              *        If data1 == 0 or data1 == 1 then use a file or font
  1076.              *        BOOPSI gadget image, else use a Gadtools text button
  1077.              *        containing the label corresponding to MSG(data1) else
  1078.              *        use string ID indicated by data1
  1079.              */
  1080.             ngbut.ng_GadgetID  = sg->promptid;
  1081.             ngbut.ng_TopEdge   = ng.ng_TopEdge;
  1082.             ngbut.ng_Height    = gheight;
  1083.             if (sg->gtype == STRING_KIND && !SquareAspect) {
  1084.                 ngbut.ng_Height  += 2;
  1085.                 ngbut.ng_TopEdge -= 1;
  1086.             }
  1087.             if (sg->data1 > SETBUTTON_MAX) {
  1088.                 /*
  1089.                  *        Creating a text gadget
  1090.                  */
  1091.                 ngbut.ng_LeftEdge   = ng.ng_LeftEdge + ng.ng_Width - miniwidth;
  1092.                 ngbut.ng_Width        = miniwidth;
  1093.                 ngbut.ng_GadgetText = MSG(sg->data1);
  1094.                 gad = CreateGadget(BUTTON_KIND, gad, &ngbut,
  1095.                                    GT_Underscore, '_',
  1096.                                    TAG_DONE);
  1097.                 if (!gad)
  1098.                     goto sgad_failed;
  1099.                 AddKeyShortcut(SetKeyboard, sg->promptid, sg->data1);
  1100.             } else {
  1101.                 /*
  1102.                  *        Creating an image gadget
  1103.                  */
  1104.                 struct Image *img = FileButtonImage;
  1105.  
  1106.                 if (sg->data1 == SETBUTTON_FONT)
  1107.                     img = FontButtonImage;
  1108.  
  1109.                 ngbut.ng_Width        = img->Width;
  1110.                 ngbut.ng_GadgetText = NULL;
  1111.                 ngbut.ng_LeftEdge   = ng.ng_LeftEdge + ng.ng_Width -img->Width;
  1112.                 gad = CreateGadget(GENERIC_KIND, gad, &ngbut, TAG_DONE);
  1113.                 if (!gad)
  1114.                     goto sgad_failed;
  1115.  
  1116.                 /*
  1117.                  *        Now fill in the details of our gadget
  1118.                  */
  1119.                 gad->Flags            |= GFLG_GADGIMAGE | GFLG_GADGHIMAGE;
  1120.                 gad->Activation     |= GACT_IMMEDIATE | GACT_RELVERIFY;
  1121.                 gad->GadgetType        |= GTYP_BOOLGADGET;
  1122.                 gad->GadgetRender    = img;
  1123.                 gad->SelectRender    = img + 1;
  1124.             }
  1125.             Gadget[sg->promptid] = gad;
  1126.             ng.ng_Width    -= ngbut.ng_Width + 2;
  1127.         }
  1128.         switch (sg->gtype) {
  1129.             case STRING_KIND:
  1130.                 if (!SquareAspect) {
  1131.                     ng.ng_Height  += 2;
  1132.                     ng.ng_TopEdge -= 1;
  1133.                 }
  1134.                 gad = CreateGadget(STRING_KIND, gad, &ng,
  1135.                                    GT_Underscore,    '_',
  1136.                                    GTST_String,        sg->data2,
  1137.                                    GTST_MaxChars,    MAX_STR_LEN,
  1138.                                    TAG_DONE);
  1139.                 break;
  1140.  
  1141.             case TEXT_KIND:
  1142.                 ng.ng_Width-= 2;
  1143.                 ng.ng_LeftEdge++;
  1144.                 gad = CreateGadget(TEXT_KIND, gad, &ng,
  1145.                                    GT_Underscore,    '_',
  1146.                                    GTTX_Text,        sg->data2,
  1147.                                    GTTX_Border,        TRUE,
  1148.                                    TAG_DONE);
  1149.                 break;
  1150.  
  1151.             case CYCLE_KIND:
  1152.             {
  1153.                 int *msgid = sg->data2;
  1154.                 char **msg = sg->data3;
  1155.                 int i;
  1156.  
  1157.                 for (i = 0; msgid[i]; i++)
  1158.                     msg[i] = MSG(msgid[i]);
  1159.                 msg[i] = NULL;
  1160.                 gad = CreateGadget(CYCLE_KIND, gad, &ng,
  1161.                                    GT_Underscore,    '_',
  1162.                                    GTCY_Active,        sg->data1,
  1163.                                    GTCY_Labels,        msg,
  1164.                                    TAG_DONE);
  1165.                 break;
  1166.             }
  1167.         }
  1168.         if (!gad)
  1169.             goto sgad_failed;
  1170.         Gadget[sg->gadgid] = gad;
  1171.         AddKeyShortcut(SetKeyboard, sg->gadgid, sg->stringid);
  1172.     }
  1173.  
  1174.     ng.ng_GadgetText    = MSG(MSG_BUFFERSIZE_GAD);
  1175.     ng.ng_GadgetID        = GID_BUFFERSIZE;
  1176.     ng.ng_TopEdge        = yoffset + spacing * 4 + (1 - SquareAspect);
  1177.     ng.ng_Height        = gheight + (2 - 2 * SquareAspect);
  1178.     ng.ng_Width            = GetTextLen(font, "10000") + 14;
  1179.     ng.ng_LeftEdge        = colpos[0] + colwidth[0] - ng.ng_Width;
  1180.  
  1181.     gad = CreateGadget(INTEGER_KIND,    gad, &ng,
  1182.                        GT_Underscore,    '_',
  1183.                        GTIN_Number,        CurSettings.Setup.BufferSize,
  1184.                        TAG_DONE);
  1185.     if (!gad)
  1186.         goto sgad_failed;
  1187.     Gadget[GID_BUFFERSIZE] = gad;
  1188.     AddKeyShortcut(SetKeyboard, GID_BUFFERSIZE, MSG_BUFFERSIZE_GAD);
  1189.  
  1190.     ng.ng_Width            = MaxTextLen(font, UseCancelUndoText) + 32;
  1191.     ng.ng_Height        = fonty + GadgetHeight;
  1192.     ng.ng_GadgetText    = MSG(MSG_USE_GAD);
  1193.     ng.ng_GadgetID        = GID_SETUSE;
  1194.     ng.ng_LeftEdge        = BorderLeft + SET_MARGIN;
  1195.     ng.ng_TopEdge        = yoffset + 7 * spacing;
  1196.     ng.ng_Flags            = PLACETEXT_IN;
  1197.  
  1198.     gad = CreateGadget(BUTTON_KIND,        gad, &ng,
  1199.                        GT_Underscore,    '_',
  1200.                        TAG_DONE);
  1201.     if (!gad)
  1202.         goto sgad_failed;
  1203.     Gadget[GID_SETUSE] = gad;
  1204.     AddKeyShortcut(SetKeyboard, GID_SETUSE, MSG_USE_GAD);
  1205.     
  1206.     ng.ng_LeftEdge        = width - BorderRight - SET_MARGIN - ng.ng_Width;
  1207.     ng.ng_GadgetText    = MSG(MSG_CANCEL_GAD);
  1208.     ng.ng_GadgetID        = GID_SETCANCEL;
  1209.  
  1210.     gad = CreateGadget(BUTTON_KIND,        gad, &ng,
  1211.                        GT_Underscore,    '_',
  1212.                        TAG_DONE);
  1213.     if (!gad)
  1214.         goto sgad_failed;
  1215.     Gadget[GID_SETCANCEL] = gad;
  1216.     AddKeyShortcut(SetKeyboard, GID_SETCANCEL, MSG_CANCEL_GAD);
  1217.     
  1218.     ng.ng_LeftEdge        = (ng.ng_LeftEdge + BorderLeft + SET_MARGIN) / 2;
  1219.     ng.ng_GadgetText    = MSG(MSG_UNDO_GAD);
  1220.     ng.ng_GadgetID        = GID_SETUNDO;
  1221.  
  1222.     gad = CreateGadget(BUTTON_KIND,        gad, &ng,
  1223.                        GT_Underscore,    '_',
  1224.                        TAG_DONE);
  1225.     if (!gad)
  1226.         goto sgad_failed;
  1227.     Gadget[GID_SETUNDO] = gad;
  1228.     AddKeyShortcut(SetKeyboard, GID_SETUNDO, MSG_UNDO_GAD);
  1229.  
  1230.     CloseFont(font);
  1231.     return (gadlist);
  1232.  
  1233. sgad_failed:
  1234.     if (gadlist)
  1235.         FreeGadgets(gadlist);
  1236.     CloseFont(font);
  1237.     return (FALSE);
  1238. }
  1239.  
  1240. /*
  1241.  *        OpenSettingsWindow()
  1242.  *
  1243.  *        Opens the settings window with all the settings gadgets.
  1244.  *        The window will contain all necessary gadgets. Note that
  1245.  *        since gadgets can take some time to create on 68000 systems,
  1246.  *        we cache the gadget list so that on subsequent re-opens of
  1247.  *        the window, we don't need to recreate them all.
  1248.  *
  1249.  *        Returns TRUE for success, false for failure.
  1250.  */
  1251. int OpenSettingsWindow(void)
  1252. {
  1253.     static struct TextAttr setfontattr =
  1254.         { "empty-storage-for-setup-fonts..", 0, FS_NORMAL, FPB_DISKFONT};
  1255.  
  1256.     static int width;        /* Maintained from call to call */
  1257.     static int height;
  1258.  
  1259.     int left = CurSettings.SetupWinLeft;
  1260.     int top  = CurSettings.SetupWinTop;
  1261.     struct TextAttr *fontattr = NULL;
  1262.     struct Window *win;
  1263.  
  1264.     CheckSegTracker();
  1265.     if (SetWindow) {
  1266.         WindowToFront(SetWindow);
  1267.         ActivateWindow(SetWindow);
  1268.         return (TRUE);
  1269.     }
  1270.     if (!CheckForScreen())
  1271.         return (FALSE);
  1272.  
  1273.     SavedSetupSets = CurSettings;        /* Save so we can restore later */
  1274.  
  1275.     if (!SetGadList) {
  1276.         /*
  1277.          *        Find out what dimensions our new window should be; to do
  1278.          *        this, we calculate the size with a variety of fonts until
  1279.          *        we find one that works.
  1280.          */
  1281.         int i;
  1282.  
  1283.         for (i = 0; fontattr = SubWindowFontList[i]; i++) {
  1284.             if (CreateSettingsGadgets(fontattr, TRUE, &width, &height))
  1285.                 break;
  1286.         }
  1287.         if (!fontattr) {
  1288.             ShowError(MSG(MSG_ERROR_OPENSET));
  1289.             return (FALSE);
  1290.         }
  1291.         /*
  1292.          *        We need to make a copy of the fontattr now so that if
  1293.          *        the user changes the font, all our gadgets don't suddenly
  1294.          *        inherit the new font (at least until the window has been
  1295.          *        closed and re-opened!)
  1296.          */
  1297.         strcpy(setfontattr.ta_Name, fontattr->ta_Name);
  1298.         setfontattr.ta_YSize = fontattr->ta_YSize;
  1299.         fontattr = &setfontattr;
  1300.     }
  1301.     if (left == -1)  left = (ScreenWidth  - width)  / 2;
  1302.     if (top  == -1)  top  = (ScreenHeight - height) / 2;
  1303.  
  1304.     win = OpenWindowTags(NULL,
  1305.                          WA_Title,            MSG(MSG_SETTINGS_TITLE),
  1306.                          WA_IDCMP,            IDCMP_CLOSEWINDOW     |
  1307.                                              IDCMP_REFRESHWINDOW     |
  1308.                                             IDCMP_NEWSIZE         |
  1309.                                             IDCMP_RAWKEY         |
  1310.                                             IDCMP_INACTIVEWINDOW |
  1311.                                             BUTTONIDCMP,
  1312.                          WA_Left,              left,
  1313.                          WA_Top,              top,
  1314.                          WA_Width,            width,
  1315.                          WA_Height,            height,
  1316.                          WA_Flags,            WFLG_DRAGBAR         |
  1317.                                              WFLG_DEPTHGADGET     |
  1318.                                             WFLG_ACTIVATE         |
  1319.                                             WFLG_RMBTRAP         |
  1320.                                             WFLG_NEWLOOKMENUS,
  1321.                          RefreshTag,          TRUE,
  1322.                          WA_NoCareRefresh,    NoCareRefreshBool,
  1323.                          WA_PubScreen,        SnoopScreen,
  1324.                          TAG_DONE);
  1325.     if (!win) {
  1326.         ShowError(MSG(MSG_ERROR_OPENSET));
  1327.         return (FALSE);
  1328.     }
  1329.     if (!SetGadList) {
  1330.         SetGadList = CreateSettingsGadgets(fontattr, 0, 0, 0);
  1331.         if (!SetGadList) {
  1332.             CloseWindow(win);
  1333.             ShowError(MSG(MSG_ERROR_OPENSET));
  1334.             return (FALSE);
  1335.         }
  1336.     }
  1337.     AddGList(win, SetGadList, -1, -1, NULL);
  1338.     RefreshGList(SetGadList, win, NULL, -1);
  1339.     GT_RefreshWindow(win, NULL);
  1340.  
  1341.     SetWindow        = win;
  1342.     SetWindowPort    = win->UserPort;
  1343.     SetWindowMask    = 1 << SetWindowPort->mp_SigBit;
  1344.     if (DisableNestCount)
  1345.         DisableWindow(SetWindow, &SetRequester);
  1346.     return (TRUE);
  1347. }
  1348.  
  1349. /*
  1350.  *        CloseFunctionWindow(void)
  1351.  *
  1352.  *        Closes the functions window. Note that we do NOT free the gadget
  1353.  *        list in this case; since it takes so long to build, we leave it
  1354.  *        alone for the benefit of future opens.
  1355.  */
  1356. void CloseFunctionWindow(void)
  1357. {
  1358.     if (FuncWindow) {
  1359.         RecordWindowSizes();
  1360.         CloseWindow(FuncWindow);
  1361.         FuncWindow     = NULL;
  1362.         FuncWindowMask = 0;
  1363.     }
  1364.     if (PurgeFuncGadgets && FuncGadList) {
  1365.         FreeGadgets(FuncGadList);
  1366.         FuncGadList       = NULL;
  1367.     }
  1368.     if (PurgeFuncGadgets && FuncVI) {
  1369.         FreeVisualInfo(FuncVI);
  1370.         FuncVI = NULL;
  1371.     }
  1372.     PurgeFuncGadgets = 0;
  1373. }
  1374.  
  1375. /*
  1376.  *        CloseSettingsWindow(void)
  1377.  *
  1378.  *        Closes the settings window, and free gadgets associated with window.
  1379.  */
  1380. void CloseSettingsWindow(void)
  1381. {
  1382.     if (SetWindow) {
  1383.         RecordWindowSizes();
  1384.         CloseWindow(SetWindow);
  1385.         SetWindow     = NULL;
  1386.         SetWindowMask = 0;
  1387.     }
  1388.     if (SetGadList) {
  1389.         FreeGadgets(SetGadList);
  1390.         SetGadList = NULL;
  1391.     }
  1392.     if (FileButtonImage) {
  1393.         FreeCustomImage(FileButtonImage);
  1394.         FileButtonImage = NULL;
  1395.     }
  1396.     if (FontButtonImage) {
  1397.         FreeCustomImage(FontButtonImage);
  1398.         FontButtonImage = NULL;
  1399.     }
  1400.     if (SetVI) {
  1401.         FreeVisualInfo(SetVI);
  1402.         SetVI = NULL;
  1403.     }
  1404. }
  1405.  
  1406. /*
  1407.  *        HandleSettingsMsgs()
  1408.  *
  1409.  *        Processes all outstanding messages associated with the Settings
  1410.  *        gadget window. To be called whenever we get a settings event.
  1411.  */
  1412.  
  1413. #define STRVAL(gid)    (((struct StringInfo *)(Gadget[gid]->SpecialInfo))->Buffer)
  1414.  
  1415. void HandleSettingsMsgs(void)
  1416. {
  1417.     static int activegad;            /* Non-zero if gadget is depressed   */
  1418.     static int activekey;            /* Keycode shortcut of activegad     */
  1419.  
  1420.     struct IntuiMessage *imsg;
  1421.     int doneset = SEL_NONE;
  1422.     char *str;
  1423.     int val;
  1424.  
  1425.     if (!SetWindow)
  1426.         return;
  1427.  
  1428.     while ((imsg = GT_GetIMsg(SetWindowPort)) != NULL) {
  1429.         struct Gadget *gad;
  1430.         int gadid;
  1431.         int shift  = (imsg->Qualifier & IE_SHIFT);
  1432.         int newval;
  1433.  
  1434.         switch (imsg->Class) {
  1435.             
  1436.             case IDCMP_CLOSEWINDOW:
  1437.                 doneset = SEL_USE;
  1438.                 break;
  1439.  
  1440.             case IDCMP_REFRESHWINDOW:
  1441.                 GT_BeginRefresh(SetWindow);
  1442.                 GT_EndRefresh(SetWindow, TRUE);
  1443.                 break;
  1444.  
  1445.             case IDCMP_MOUSEMOVE: 
  1446.             case IDCMP_GADGETDOWN:
  1447.             case IDCMP_GADGETUP:
  1448.                 gad    = (struct Gadget *)imsg->IAddress;
  1449.                 gadid  = gad->GadgetID;
  1450.                 newval = imsg->Code;
  1451.  
  1452. handle_set_gads:
  1453.                 switch (gadid) {
  1454.  
  1455.                     case GID_FILEPROMPT:
  1456.                     {
  1457.                         char *defname = "";
  1458.  
  1459.                         /*
  1460.                          *        Choose a default name for the logfile
  1461.                          */
  1462.                         if (IsFileSystem(DefaultLogName))
  1463.                             defname = DefaultLogName;
  1464.  
  1465.                         if (SelectFile(DefaultLogName, defname, SetWindow,
  1466.                                        FILESEL_DEFLOGNAME))
  1467.                         {
  1468.                             /*
  1469.                              *        Got a new default filename, so update
  1470.                              *        the logfile gadget accordingly
  1471.                              */
  1472.                             GT_SetGadgetAttrs(Gadget[GID_LOGFILE],
  1473.                                               SetWindow, NULL,
  1474.                                                 GTST_String, DefaultLogName,
  1475.                                                 TAG_DONE);
  1476.                         }
  1477.                         break;
  1478.                     }
  1479.  
  1480.                     case GID_WFONTPROMPT:
  1481.                         /*
  1482.                          *        Choose a new gadget (window) font
  1483.                          */
  1484.                         if (SelectFont(SetWindow, FONTSEL_WINDOW)) {
  1485.                             strcpy(WindowFontName, WindowFR->fo_Attr.ta_Name);
  1486.                             WindowFontSize = WindowFR->fo_Attr.ta_YSize;
  1487.                             WindowFontAttr.ta_YSize    = WindowFontSize;
  1488.  
  1489.                             GT_SetGadgetAttrs(
  1490.                                 Gadget[GID_WINDOWFONT], SetWindow, NULL,
  1491.                                 GTTX_Text, GetFontDesc(WindowFontDesc,
  1492.                                                        WindowFontName,
  1493.                                                        WindowFontSize),
  1494.                                 TAG_DONE);
  1495.                             ReOpenMainWindow();
  1496.                             WindowToFront(SetWindow);
  1497.                             /*
  1498.                              *        Since we allow the function gadgets
  1499.                              *        to hang around even when the function
  1500.                              *        window closes, we need to free the
  1501.                              *        gadgets when we change fonts to force
  1502.                              *        them to be regenerated in the new
  1503.                              *        font.
  1504.                              */        
  1505.                             if (!FuncWindow) {
  1506.                                 FreeGadgets(FuncGadList);
  1507.                                 FuncGadList         = NULL;
  1508.                             } else {
  1509.                                 PurgeFuncGadgets = TRUE;
  1510.                             }
  1511.                         }
  1512.                         break;
  1513.  
  1514.                     case GID_BFONTPROMPT:
  1515.                         /*
  1516.                          *        Choose a new buffer font
  1517.                          */
  1518.                         if (SelectFont(SetWindow, FONTSEL_BUFFER)) {
  1519.                             strcpy(BufferFontName, BufferFR->fo_Attr.ta_Name);
  1520.                             BufferFontSize = BufferFR->fo_Attr.ta_YSize;
  1521.                             BufferFontAttr.ta_YSize    = BufferFontSize;
  1522.  
  1523.                             GT_SetGadgetAttrs(
  1524.                                 Gadget[GID_BUFFERFONT],
  1525.                                 SetWindow, NULL,
  1526.                                 GTTX_Text, GetFontDesc(BufferFontDesc,
  1527.                                                        BufferFontName,
  1528.                                                          BufferFontSize),
  1529.                                 TAG_DONE);
  1530.                             ReOpenMainWindow();
  1531.                             WindowToFront(SetWindow);
  1532.                         }
  1533.                         break;
  1534.  
  1535.                     case GID_FORMATEDIT:
  1536.                         OpenFormatWindow();
  1537.                         break;
  1538.  
  1539.                     case GID_FORMATCOPY:
  1540.                         if (shift)
  1541.                             *LogFormat = '\0';
  1542.                         else
  1543.                             strcpy(LogFormat, BufFormat);
  1544.                         GT_SetGadgetAttrs(Gadget[GID_LOGFORMAT],
  1545.                                           SetWindow, NULL,
  1546.                                           GTST_String, LogFormat,
  1547.                                           TAG_DONE);
  1548.                         break;
  1549.  
  1550.                     case GID_FILEIO:
  1551.                         CurSettings.Setup.FileIOType = newval;
  1552.                         break;
  1553.  
  1554.                     case GID_OPENON:
  1555.                         CurSettings.Setup.ScreenType = newval;
  1556.                         break;
  1557.  
  1558.                     case GID_LOGMODE:
  1559.                         CurSettings.Setup.LogMode     = newval;
  1560.                         SetLogGadget(newval, LG_REFRESH);
  1561.                         break;
  1562.  
  1563.                     case GID_HIDEMETHOD:
  1564.                         if (!CxBase)
  1565.                             newval = 0;
  1566.  
  1567.                         if (newval != CurSettings.Setup.HideMethod) {
  1568.                             int oldval = CurSettings.Setup.HideMethod;
  1569.  
  1570.                             CurSettings.Setup.HideMethod = newval;
  1571.                             if (newval == HIDE_NONE)
  1572.                                 CleanupHotKey();
  1573.                             else if (oldval == HIDE_NONE) {
  1574.                                 /*
  1575.                                  *        Switching out of hide state so
  1576.                                  *        re-activate hotkey
  1577.                                  */
  1578.                                 InstallHotKey(CurSettings.Setup.HotKey);
  1579.                             }
  1580.                             SetMainHideState(newval);
  1581.                         }
  1582.                         break;
  1583.  
  1584.                     case GID_HOTKEY:
  1585.                     {
  1586.                         char *msg = CurSettings.Setup.HotKey;
  1587.  
  1588.                         strcpy(msg, STRVAL(GID_HOTKEY));
  1589.                         InstallHotKey(msg);
  1590.                         SetMainHideState(CurSettings.Setup.HideMethod);
  1591.                         break;
  1592.                     }
  1593.  
  1594.                     case GID_SCREENNAME:
  1595.                         strcpy(CurSettings.Setup.ScreenName,
  1596.                                STRVAL(GID_SCREENNAME));
  1597.                         break;
  1598.  
  1599.                     case GID_LOGFILE:
  1600.                         strcpy(CurSettings.Setup.LogFile, STRVAL(GID_LOGFILE));
  1601.                         break;
  1602.  
  1603.                     case GID_LOGFORMAT:
  1604.                         strcpy(CurSettings.Setup.LogfileFormat,
  1605.                                STRVAL(GID_LOGFORMAT));
  1606.                         break;
  1607.  
  1608.                     case GID_BUFFORMAT:
  1609.                         str = STRVAL(GID_BUFFORMAT);
  1610.                         if (strcmp(BufFormat, str) != 0) {
  1611.                             strcpy(BufFormat, str);
  1612.                             InstallNewFormat(NEW_STRING);
  1613.                         }
  1614.                         break;
  1615.  
  1616.                     case GID_BUFFERSIZE:
  1617.                         /*
  1618.                          *        We don't do anything here at all ... instead,
  1619.                          *        the update is handled when the user clicks
  1620.                          *        on USE.
  1621.                          */
  1622.                         break;
  1623.  
  1624.                     case GID_SETUSE:
  1625.                         doneset = SEL_USE;
  1626.                         break;
  1627.  
  1628.                     case GID_SETCANCEL:
  1629.                         doneset = SEL_CANCEL;
  1630.                         break;
  1631.  
  1632.                     case GID_SETUNDO:
  1633.                         /*
  1634.                          *        Major bummer -- we need to manually update
  1635.                          *        ALL the string gadgets, since if the user
  1636.                          *        modified one of them and didn't press RETURN
  1637.                          *        we won't have picked it up and so we won't
  1638.                          *        know to undo it :-(
  1639.                          */
  1640.                         InstallSettings(&SavedSetupSets, SET_SETUP);
  1641.  
  1642. #define UndoSet SavedSetupSets.Setup
  1643.  
  1644.                         GT_SetGadgetAttrs(Gadget[GID_HOTKEY],
  1645.                                           SetWindow, NULL,
  1646.                                           GTST_String, UndoSet.HotKey,
  1647.                                           TAG_DONE);
  1648.                         GT_SetGadgetAttrs(Gadget[GID_SCREENNAME],
  1649.                                           SetWindow, NULL,
  1650.                                           GTST_String, UndoSet.ScreenName,
  1651.                                           TAG_DONE);
  1652.                         GT_SetGadgetAttrs(Gadget[GID_LOGFILE],
  1653.                                           SetWindow, NULL,
  1654.                                           GTST_String, UndoSet.LogFile,
  1655.                                           TAG_DONE);
  1656.                         GT_SetGadgetAttrs(Gadget[GID_BUFFORMAT],
  1657.                                           SetWindow, NULL,
  1658.                                           GTST_String, UndoSet.BufferFormat,
  1659.                                           TAG_DONE);
  1660.                         GT_SetGadgetAttrs(Gadget[GID_LOGFORMAT],
  1661.                                           SetWindow, NULL,
  1662.                                           GTST_String, UndoSet.LogfileFormat,
  1663.                                           TAG_DONE);
  1664.                         GT_SetGadgetAttrs(Gadget[GID_BUFFERSIZE],
  1665.                                           SetWindow, NULL,
  1666.                                             GTIN_Number, UndoSet.BufferSize,
  1667.                                           TAG_DONE);
  1668.                         break;
  1669.                 }
  1670.                 break;
  1671.  
  1672.             case IDCMP_INACTIVEWINDOW:
  1673.                 if (activegad) {
  1674.                     ShowGadget(SetWindow, Gadget[activegad], GADGET_UP);
  1675.                     activegad = 0;
  1676.                 }
  1677.                 break;
  1678.  
  1679.             case IDCMP_RAWKEY:
  1680.             {
  1681.                 int upstroke = imsg->Code & 0x80;
  1682.                 int keypress = ConvertIMsgToChar(imsg);
  1683.  
  1684.                 gadid  = SetKeyboard[keypress];
  1685.                 if (activegad) {
  1686.                     /*
  1687.                      *        We're releasing a gadget that was pressed
  1688.                      *        earlier, so handle it now
  1689.                      */
  1690.                     int samekey = (imsg->Code & 0x7f) == activekey;
  1691.  
  1692.                     if (samekey && !upstroke)    /* Ignore repeated keys */
  1693.                         break;
  1694.  
  1695.                     ShowGadget(SetWindow, Gadget[activegad], GADGET_UP);
  1696.                     if (samekey) {
  1697.                         /*
  1698.                          *        Just released the key that was originally
  1699.                          *        pressed for this gadget, so now go and
  1700.                          *        handle the gadget action.
  1701.                          */
  1702.                         gadid     = activegad;
  1703.                         gad       = Gadget[gadid];
  1704.                         activegad = 0;
  1705.                         goto handle_set_gads;
  1706.                     }
  1707.  
  1708.                     /*
  1709.                      *        If the above check didn't kick in, it means
  1710.                      *        we got a downpress of a different key, so
  1711.                      *        disable the gadget for this key and continue
  1712.                      *        to press the other key.
  1713.                      */
  1714.                     activegad = 0;
  1715.                 }
  1716.  
  1717.                 if (imsg->Code == HELPKEY) {
  1718.                     ShowAGuide(MSG(MSG_LINK_SETUPWIN));
  1719.                     break;
  1720.                 }
  1721.  
  1722.                 /*
  1723.                  *        Handle keyboard equivalent keypresses for gadgets
  1724.                  */
  1725.                 if (gadid) {
  1726.                     int numopts;
  1727.  
  1728.                     gad = Gadget[gadid];
  1729.  
  1730.                     switch (gadid) {
  1731.                         case GID_HIDEMETHOD:
  1732.                             newval  = CurSettings.Setup.HideMethod;
  1733.                             numopts = HIDE_MAX;
  1734.                             goto handle_set_cycle;
  1735.  
  1736.                         case GID_OPENON:
  1737.                             newval  = CurSettings.Setup.ScreenType;
  1738.                             numopts = SCREEN_MAX;
  1739.                             goto handle_set_cycle;
  1740.  
  1741.                         case GID_LOGMODE:
  1742.                             newval  = CurSettings.Setup.LogMode;
  1743.                             numopts = LOGMODE_MAX;
  1744.                             goto handle_set_cycle;
  1745.  
  1746.                         case GID_FILEIO:
  1747.                             newval  = CurSettings.Setup.FileIOType;
  1748.                             numopts = FILE_MAX;
  1749. handle_set_cycle:
  1750.                             newval++;
  1751.                             if (shift)
  1752.                                 newval -= 2;
  1753.                             if (newval < 0)            newval += numopts;
  1754.                             if (newval >= numopts)    newval -= numopts;
  1755.                             GT_SetGadgetAttrs(gad, SetWindow, NULL,
  1756.                                                 GTCY_Active, newval,
  1757.                                                 TAG_DONE);
  1758.                             goto handle_set_gads;
  1759.  
  1760.                         case GID_BUFFERSIZE:
  1761.                         case GID_BUFFORMAT:
  1762.                         case GID_LOGFORMAT:
  1763.                         case GID_HOTKEY:
  1764.                         case GID_SCREENNAME:
  1765.                         case GID_LOGFILE:
  1766.                             if (gadid != GID_LOGFILE || !shift) {
  1767.                                 ActivateGadget(gad, SetWindow, NULL);
  1768.                                 break;
  1769.                             }
  1770.                             /*
  1771.                              *        User pressed GID_LOGFILE with SHIFT
  1772.                              *        pressed, so change gadget type to
  1773.                              *        GID_FILEPROMPT and fall through to
  1774.                              *        button code.
  1775.                              */
  1776.                             gadid = GID_FILEPROMPT;
  1777.                             /* Fall through */
  1778.  
  1779.                         case GID_SETUSE:
  1780.                         case GID_SETUNDO:
  1781.                         case GID_SETCANCEL:
  1782.                         case GID_FORMATCOPY:
  1783.                         case GID_FORMATEDIT:
  1784.                         case GID_WINDOWFONT:
  1785.                         case GID_BUFFERFONT:
  1786.                         case GID_WFONTPROMPT:
  1787.                         case GID_BFONTPROMPT:
  1788.                             if (gadid == GID_WINDOWFONT)
  1789.                                 gadid = GID_WFONTPROMPT;
  1790.                             if (gadid == GID_BUFFERFONT)
  1791.                                 gadid = GID_BFONTPROMPT;
  1792.                             gad = Gadget[gadid];
  1793.                             ShowGadget(SetWindow, gad, GADGET_DOWN);
  1794.                             activegad = gadid;
  1795.                             activekey = imsg->Code;
  1796.                             break;
  1797.                     }
  1798.                 }
  1799.                 break;
  1800.             }
  1801.         }
  1802.         GT_ReplyIMsg(imsg);
  1803.     }
  1804.     /*
  1805.      *        Handled all messages. Now check for possible USE/CANCEL
  1806.      */
  1807.     if (doneset == SEL_USE) {
  1808.         /*
  1809.          *        Use the current settings. To be safe, we update all
  1810.          *        our string gadgets in case they were modified but
  1811.          *        we didn't catch the modification (i.e. user didn't press
  1812.          *        Return).
  1813.          */
  1814.         str = STRVAL(GID_BUFFORMAT);
  1815.         if (strcmp(BufFormat, str) != 0) {
  1816.             strcpy(BufFormat, str);
  1817.             InstallNewFormat(NEW_STRING);
  1818.         }
  1819.         strcpy(CurSettings.Setup.LogFile,          STRVAL(GID_LOGFILE));
  1820.         strcpy(CurSettings.Setup.ScreenName,      STRVAL(GID_SCREENNAME));
  1821.         strcpy(CurSettings.Setup.HotKey,          STRVAL(GID_HOTKEY));
  1822.         strcpy(CurSettings.Setup.LogfileFormat,     STRVAL(GID_LOGFORMAT));
  1823.         strcpy(CurSettings.Setup.LogfileFormat,  STRVAL(GID_LOGFORMAT));
  1824.         val = atoi(STRVAL(GID_BUFFERSIZE));
  1825.         CloseSettingsWindow();
  1826.         /*
  1827.          *        Now check if we've got a new buffer size --
  1828.          *        if so, install it.
  1829.          */
  1830.         if (val < 1)
  1831.             val = 1;
  1832.  
  1833.         if (val != SavedSetupSets.Setup.BufferSize) {
  1834.             CurSettings.Setup.BufferSize = val;
  1835.             ClearWindowBuffer();
  1836.             if (!SetTotalBufferSize(val * 1024, SETBUF_FORCENEW)) {
  1837.                 ShowError(MSG(MSG_ERROR_NOBUFMEM), val);
  1838.                 Cleanup(20);
  1839.             }
  1840.         }
  1841.     } else if (doneset == SEL_CANCEL) {
  1842.         /*
  1843.          *        Cancel the current settings, and restore those that
  1844.          *        were in effect before we started this. We close
  1845.          *        the settings window first in case the main window
  1846.          *        needs to close and re-open (change of font) since
  1847.          *        this looks cleaner.
  1848.          *
  1849.          *        Note that even though we saved the entire set of settings,
  1850.          *        we only restore the SETUP settings, not all of them.
  1851.          */
  1852.         CloseSettingsWindow();
  1853.         InstallSettings(&SavedSetupSets, SET_SETUP);
  1854.     }
  1855. }
  1856.  
  1857. /*
  1858.  *        ShowFuncOpts(options, firstid, lastid)
  1859.  *
  1860.  *        Updates the function window gadgets to reflect the new values
  1861.  *        in the specified options array.
  1862.  *
  1863.  *        The new options are compared with the existing options to see
  1864.  *        if they've changed, so you should make sure to call this function
  1865.  *        _before_ copying the new options onto the current settings.
  1866.  *
  1867.  *        Only gadgets from the first to the last ID given are affected.
  1868.  */
  1869. void ShowFuncOpts(UBYTE newopts[], int firstid, int lastid)
  1870. {
  1871.     int i;
  1872.  
  1873.     for (i = firstid; i <= lastid; i++) {
  1874.         if (Gadget[i] != NULL && newopts[i] != CurSettings.Func.Opts[i]) {
  1875.             GT_SetGadgetAttrs(Gadget[i], FuncWindow, NULL,
  1876.                               GTCB_Checked, newopts[i],
  1877.                               TAG_DONE);
  1878.         }
  1879.     }
  1880. }
  1881.  
  1882. /*
  1883.  *        ResetFuncToSelected()
  1884.  *
  1885.  *        Changes the two cycle gadgets in the function window back to the
  1886.  *        SELECTED state, and updates the variables accordingly. Note
  1887.  *        that doesn't change the actual boolean settings themselves; in
  1888.  *        effect, it makes the current settings permanent by stopping you
  1889.  *        switching back to the SELECTED state to restore an older set
  1890.  *        by clicking on the cycle gadget yourself.
  1891.  */
  1892. void ResetFuncToSelected(void)
  1893. {
  1894.     if (FuncSystemCol != COL_SELECTED) {
  1895.         GT_SetGadgetAttrs(Gadget[GID_SELSYSTEM],
  1896.                           FuncWindow, NULL,
  1897.                           GTCY_Active, COL_SELECTED,
  1898.                           TAG_DONE);
  1899.     }
  1900.     if (FuncDOSCol != COL_SELECTED) {
  1901.         GT_SetGadgetAttrs(Gadget[GID_SELDOS],
  1902.                           FuncWindow, NULL,
  1903.                           GTCY_Active, COL_SELECTED,
  1904.                           TAG_DONE);
  1905.     }
  1906.     FuncSystemCol = COL_SELECTED;
  1907.     FuncDOSCol    = COL_SELECTED;
  1908. }
  1909.  
  1910. /*
  1911.  *        HandleFuncMsgs()
  1912.  *
  1913.  *        Processes all outstanding messages associated with the Functions
  1914.  *        gadget window. To be called whenever we get a functions event.
  1915.  *
  1916.  *        The only slightly complicated bit here concerns the two cycle
  1917.  *        gadgets which can be used to select all or none of either of
  1918.  *        the DOS and System columns, or to restore a previous setting
  1919.  *        installed before.
  1920.  */
  1921. void HandleFuncMsgs(void)
  1922. {
  1923.     static int activegad;            /* Non-zero if gadget is depressed   */
  1924.     static int activekey;            /* Keycode shortcut of activegad     */
  1925.  
  1926.     struct IntuiMessage *imsg;
  1927.     int donefunc = SEL_NONE;
  1928.  
  1929.     if (!FuncWindow)
  1930.         return;
  1931.  
  1932.     while ((imsg = GT_GetIMsg(FuncWindowPort)) != NULL) {
  1933.         struct Gadget *gad;
  1934.         int shift = (imsg->Qualifier & IE_SHIFT);
  1935.         LONG gadid;
  1936.         int newval;
  1937.  
  1938.         switch (imsg->Class) {
  1939.             
  1940.             case IDCMP_REFRESHWINDOW:
  1941.                 GT_BeginRefresh(FuncWindow);
  1942.                 GT_EndRefresh(FuncWindow, TRUE);
  1943.                 break;
  1944.  
  1945.             case IDCMP_CLOSEWINDOW:
  1946.                 donefunc = SEL_USE;
  1947.                 break;
  1948.  
  1949.             case IDCMP_MOUSEMOVE: 
  1950.             case IDCMP_GADGETDOWN:
  1951.             case IDCMP_GADGETUP:
  1952.                 gad    = (struct Gadget *)imsg->IAddress;
  1953.                 gadid  = gad->GadgetID;
  1954.                 newval = imsg->Code;
  1955.  
  1956. handle_func_gads:
  1957.  
  1958.                 switch (gadid) {
  1959.  
  1960.                     case GID_MATCHNAME:
  1961.                         strcpy(MatchName, STRVAL(GID_MATCHNAME));
  1962.                         SetPattern(MatchName, IgnoreWBShell);
  1963.                         break;
  1964.  
  1965.                     case GID_SELSYSTEM:
  1966.                     case GID_SELDOS:
  1967.                         /*
  1968.                          *        Changing system column cycle gadget.
  1969.                          *        Update to show ALL, NONE or SELECTED
  1970.                          *        system gadgets.
  1971.                          */
  1972.                     {
  1973.                         int first    = FIRST_SYS_GADGET;
  1974.                         int last     = LAST_SYS_GADGET;
  1975.                         int numgads  = NUM_SYS_GADGETS;
  1976.                         int *pcurval = &FuncSystemCol;
  1977.  
  1978.                         if (gadid == GID_SELDOS) {
  1979.                             /*
  1980.                              *        Override above defaults with new
  1981.                              *        defaults for DOS cycle gadget
  1982.                              */
  1983.                             first    = FIRST_DOS_GADGET;
  1984.                             last     = LAST_DOS_GADGET;
  1985.                             numgads  = NUM_DOS_GADGETS;
  1986.                             pcurval     = &FuncDOSCol;
  1987.                         }
  1988.                         if (newval == *pcurval)
  1989.                             break;        /* Ignore no-op events */
  1990.  
  1991.                         if (newval == COL_SELECTED) {
  1992.                             /*
  1993.                              *        Restore previously saved system col values
  1994.                              */
  1995.                             ShowFuncOpts(SavedCols, first, last);
  1996.                             memcpy(&CurSettings.Func.Opts[first],
  1997.                                    &SavedCols[first], numgads);
  1998.                         } else {
  1999.                             /*
  2000.                              *        Select either ALL or NONE of the settings
  2001.                              *        in the system column.
  2002.                              */
  2003.                             int fillval = (newval == COL_ALL);
  2004.  
  2005.                             memset(&TempCols[first], fillval, numgads);
  2006.                             ShowFuncOpts(TempCols, first, last);
  2007.                                     
  2008.                             if (*pcurval == COL_SELECTED) {
  2009.                                /*
  2010.                                 *        If we are moving out of the
  2011.                                 *        selected state, then save the
  2012.                                 *        existing settings for later.
  2013.                                 */
  2014.                                memcpy(&SavedCols[first],
  2015.                                          &CurSettings.Func.Opts[first], numgads);
  2016.                             }
  2017.                             memset(&CurSettings.Func.Opts[first],
  2018.                                    fillval, numgads);
  2019.                         }
  2020.                         LoadFuncSettings(&CurSettings.Func);
  2021.                         *pcurval = newval;
  2022.                         break;
  2023.                     }
  2024.  
  2025.                     case GID_FUNCUSE:
  2026.                         /*
  2027.                          *        Retain existing settings, and exit
  2028.                          */
  2029.                         donefunc = SEL_USE;
  2030.                         break;
  2031.  
  2032.                     case GID_FUNCCANCEL:
  2033.                         /*
  2034.                          *        Restore original settings and exit
  2035.                          */
  2036.                         donefunc = SEL_CANCEL;
  2037.                         break;
  2038.  
  2039.                     case GID_FUNCUNDO:
  2040.                         /*
  2041.                          *        Restore original settings but don't exit
  2042.                          */
  2043.                         InstallSettings(&SavedFuncSets, SET_FUNC);
  2044.                         break;
  2045.  
  2046.                     default:
  2047.                         if (gadid >= FIRST_BOOL_GADGET &&
  2048.                                                 gadid <= LAST_BOOL_GADGET) {
  2049.                             /*
  2050.                              *        Getting a new boolean gadget so update
  2051.                              *        CurSettings to reflect this.
  2052.                              */
  2053.                             CurSettings.Func.Opts[gadid] =
  2054.                                         (gad->Flags & GFLG_SELECTED) != 0;
  2055.                             LoadFuncSettings(&CurSettings.Func);
  2056.                             /*
  2057.                              *        Now check to see if we need to put
  2058.                              *        either column back into the selected
  2059.                              *        state again.
  2060.                              */
  2061.                             if (FuncSystemCol != COL_SELECTED &&
  2062.                                 gadid >= FIRST_SYS_GADGET      &&
  2063.                                 gadid <= LAST_SYS_GADGET)
  2064.                             {
  2065.                                 FuncSystemCol = COL_SELECTED;
  2066.                                 GT_SetGadgetAttrs(Gadget[GID_SELSYSTEM],
  2067.                                                   FuncWindow, NULL,
  2068.                                                   GTCY_Active, COL_SELECTED,
  2069.                                                   TAG_DONE);
  2070.                             }
  2071.                             if (FuncDOSCol != COL_SELECTED    &&
  2072.                                 gadid >= FIRST_DOS_GADGET    &&
  2073.                                 gadid <= LAST_DOS_GADGET)
  2074.                             {
  2075.                                 FuncDOSCol = COL_SELECTED;
  2076.                                 GT_SetGadgetAttrs(Gadget[GID_SELDOS],
  2077.                                                   FuncWindow, NULL,
  2078.                                                   GTCY_Active, COL_SELECTED,
  2079.                                                   TAG_DONE);
  2080.                             }
  2081.                         }
  2082.                         break;
  2083.                 }
  2084.                 break;
  2085.  
  2086.             case IDCMP_INACTIVEWINDOW:
  2087.                 if (activegad) {
  2088.                     ShowGadget(FuncWindow, Gadget[activegad], GADGET_UP);
  2089.                     activegad = 0;
  2090.                 }
  2091.                 break;
  2092.  
  2093.             case IDCMP_RAWKEY:
  2094.             {
  2095.                 int upstroke = imsg->Code & 0x80;
  2096.                 int keypress = ConvertIMsgToChar(imsg);
  2097.  
  2098.                 gadid  = FuncKeyboard[keypress];
  2099.                 if (activegad) {
  2100.                     /*
  2101.                      *        We're releasing a gadget that was pressed
  2102.                      *        earlier, so handle it now
  2103.                      */
  2104.                     int samekey = (imsg->Code & 0x7f) == activekey;
  2105.  
  2106.                     if (samekey && !upstroke)    /* Ignore repeated keys */
  2107.                         break;
  2108.  
  2109.                     ShowGadget(FuncWindow, Gadget[activegad], GADGET_UP);
  2110.                     if (samekey) {
  2111.                         /*
  2112.                          *        Just released the key that was originally
  2113.                          *        pressed for this gadget, so now go and
  2114.                          *        handle the gadget action.
  2115.                          */
  2116.                         gadid     = activegad;
  2117.                         gad       = Gadget[gadid];
  2118.                         activegad = 0;
  2119.                         goto handle_func_gads;
  2120.                     }
  2121.                     /*
  2122.                      *        If the above check didn't kick in, it means
  2123.                      *        we got a downpress of a different key, so
  2124.                      *        disable the gadget for this key and continue
  2125.                      *        to press the other key.
  2126.                      */
  2127.                     activegad = 0;
  2128.                 }
  2129.  
  2130.                 if (imsg->Code == HELPKEY) {
  2131.                     ShowAGuide(MSG(MSG_LINK_FUNCWIN));
  2132.                     break;
  2133.                 }
  2134.  
  2135.                 /*
  2136.                  *        Handle keyboard equivalents for gadgets
  2137.                  */
  2138.                 gadid = FuncKeyboard[keypress];
  2139.                 if (gadid) {
  2140.                     gad = Gadget[gadid];
  2141.  
  2142.                     if (gadid >= FIRST_BOOL_GADGET &&
  2143.                                         gadid <= LAST_BOOL_GADGET) {
  2144.                         /*
  2145.                          *        It's a boolean gadget so just invert its
  2146.                          *        current setting
  2147.                          */
  2148.                         newval = !CurSettings.Func.Opts[gadid];
  2149.                         GT_SetGadgetAttrs(Gadget[gadid], FuncWindow, NULL,
  2150.                                           GTCB_Checked, newval, TAG_DONE);
  2151.                         goto handle_func_gads;
  2152.                     } else if (gadid == GID_SELSYSTEM || gadid == GID_SELDOS) {
  2153.                         /*
  2154.                          *        One of the two cycle gadgets. Cycle forward
  2155.                          *        if the unshifted key was pressed or back
  2156.                          *        if the shifted version was pressed
  2157.                          */
  2158.                         newval = FuncSystemCol;
  2159.                         if (gadid == GID_SELDOS)
  2160.                             newval = FuncDOSCol;
  2161.                         newval++;
  2162.                         if (shift)
  2163.                             newval -= 2;
  2164.                         if (newval < 0)    newval = 2;
  2165.                         if (newval > 2) newval = 0;
  2166.                         GT_SetGadgetAttrs(gad, FuncWindow, NULL,
  2167.                                           GTCY_Active, newval, TAG_DONE);
  2168.                         goto handle_func_gads;
  2169.                     } else if (gadid == GID_MATCHNAME) {
  2170.                         /* 
  2171.                          *        The string gadget, so simply activate it
  2172.                          */
  2173.                         ActivateGadget(gad, FuncWindow, NULL);
  2174.                     } else {
  2175.                         /*
  2176.                          *        It must be a button gadget so show it
  2177.                          *        selected first before processing it
  2178.                          */
  2179.                         ShowGadget(FuncWindow, gad, GADGET_DOWN);
  2180.                         activegad = gadid;
  2181.                         activekey = imsg->Code;
  2182.                     }
  2183.                 }
  2184.                 break;
  2185.             }
  2186.         }
  2187.         GT_ReplyIMsg(imsg);
  2188.     }
  2189.     if (donefunc != SEL_NONE) {
  2190.         /*
  2191.          *        Since we cache the function gadgets between window opens,
  2192.          *        we need to ensure the two cycle gadgets are reset to
  2193.          *        SELECTED mode ready for the next time we open the window.
  2194.          *        (Ideally, we would remember the cycle state and use the
  2195.          *        same state next time, but that's too much work!)
  2196.          */
  2197.         ResetFuncToSelected();
  2198.     }
  2199.     if (donefunc == SEL_USE) {
  2200.         strcpy(MatchName, STRVAL(GID_MATCHNAME));
  2201.         SetPattern(MatchName, IgnoreWBShell);
  2202.         CloseFunctionWindow();
  2203.     } else if (donefunc == SEL_CANCEL) {
  2204.         CloseFunctionWindow();
  2205.         /*
  2206.          *        Note that though we saved all the settings, we only
  2207.          *        re-install the original function settings, not all
  2208.          *        of them.
  2209.          */
  2210.         InstallSettings(&SavedFuncSets, SET_FUNC);
  2211.     }
  2212. }
  2213.  
  2214. /*
  2215.  *        CreateFormatGadgets(gadgetfa, bufferfa, getsize, &width, &height)
  2216.  *
  2217.  *        Creates all the gadgets for the format window. If getsize
  2218.  *        is true, then the width and height values are filled in with
  2219.  *        the dimensions of the window needed to hold the gadgets. In
  2220.  *        this case, NULL is returned if the window would be too big to
  2221.  *        fit on the current screen, or non-NULL if width and height
  2222.  *        were successfully initialised.
  2223.  *
  2224.  *        gadgetfa gives the gadget font to use, bufferfa gives the buffer
  2225.  *        font (for the format listings).
  2226.  *
  2227.  *        If getsize is zero, then the actual gadgets are created and
  2228.  *        a pointer to the gadget list is returned, or NULL if an
  2229.  *        error occurred (typically, out of memory).
  2230.  */
  2231. struct Gadget *CreateFormatGadgets(struct TextAttr *gadgetfa,
  2232.                                    struct TextAttr *bufferfa,
  2233.                                    int getsize, int *pwidth, int *pheight)
  2234. {
  2235.     struct TextFont *gfont;
  2236.     struct TextFont *bfont;
  2237.     struct NewGadget ng;
  2238.     struct Gadget *gadlist;
  2239.     struct Gadget *gad;
  2240.     FieldInit *fi;
  2241.     int width;
  2242.     int height;
  2243.     int gwidth;
  2244.     int gheight;
  2245.     int gfonty;
  2246.     int bfontx;
  2247.     int bfonty;
  2248.     int topline;
  2249.     int maxtitlelen;
  2250.     int buttonwidth;
  2251.     int buttonspace;
  2252.     int headingspace;
  2253.     int outmargin;
  2254.  
  2255.     if (!FormVI) {
  2256.         FormVI = GetVisualInfoA(SnoopScreen, NULL);
  2257.         if (!FormVI)
  2258.             return (NULL);
  2259.     }
  2260.     gfont = MyOpenFont(gadgetfa);
  2261.     if (!gfont)
  2262.         return (NULL);
  2263.  
  2264.     bfont = MyOpenFont(bufferfa);
  2265.     if (!bfont) {
  2266.         CloseFont(gfont);
  2267.         return (NULL);
  2268.     }
  2269.     if (bfont->tf_Flags & FPF_PROPORTIONAL) {
  2270.         CloseFont(bfont);
  2271.         CloseFont(gfont);
  2272.         return (NULL);
  2273.     }
  2274.     bfontx        = bfont->tf_XSize;
  2275.     bfonty        = bfont->tf_YSize;
  2276.     gfonty        = gfont->tf_YSize;
  2277.     gheight        = gfonty  + 3;
  2278.     gwidth         = gheight + 15;
  2279.     topline     = TitlebarHeight + gfonty/2;
  2280.  
  2281.     /*
  2282.      *        Now calculate the width of the window boxes which will contain
  2283.      *        the format sequences being displayed. The defaults box must be
  2284.      *        wide enough to hold "titlemsg..  %x" whereas the current format
  2285.      *        box must be wide enough to hold "titlemsg..  %20x".
  2286.      *
  2287.      *        Since the message titles may be localised, we calculate the
  2288.      *        longest string and work from that.
  2289.      */
  2290.     maxtitlelen = 0;
  2291.     for (fi = FieldTypes; fi->type != EF_END; fi++) {
  2292.         int len = strlen(MSG(fi->titlemsgid));
  2293.  
  2294.         if (len > maxtitlelen)
  2295.             maxtitlelen = len;
  2296.     }
  2297.     /*
  2298.      *        The next two vars give the number of characters that will fit
  2299.      *        across each box. These is used when producing output.
  2300.      *
  2301.      *        For the left box, this is the length of the longest heading title,
  2302.      *        plus 2 for spacing after the heading name, another 2 for the
  2303.      *        format ID (%x) and a final 2 for the spacing on either side.
  2304.      *
  2305.      *        The right box is similar, but uses an additional 2 characters to
  2306.      *        display the field width of the selected item.
  2307.      */
  2308.     FBoxA_NumChars    = maxtitlelen   + 6;
  2309.     FBoxB_NumChars    = FBoxA_NumChars + 2;
  2310.     FBoxA_Width     = FBoxA_NumChars * bfontx + 4;
  2311.     FBoxB_Width     = FBoxB_NumChars * bfontx + 4;
  2312.  
  2313.     /*
  2314.      *        Create format strings for sprintf formatting later on. These
  2315.      *        look like this:
  2316.      *
  2317.      *            FBoxA_FormString:    " %-??s  %%%lc "        (2 parameters)
  2318.      *            FBoxB_FormString:    " %-??s  %%%02ld%lc "    (3 parameters)
  2319.      *
  2320.      *        and when strings are output using these templates, they look like:
  2321.      *
  2322.      *            FBoxA_FormString:    " PaddedTitleName....  %x "
  2323.      *            FBoxB_FormString:   " PaddedTitleName....  %12x "
  2324.      */
  2325.     mysprintf(FBoxA_FormString, " %%-%lds  %%%%%%lc ",         maxtitlelen);
  2326.     mysprintf(FBoxB_FormString, " %%-%lds  %%%%%%02ld%%lc ", maxtitlelen);
  2327.  
  2328.     /*
  2329.      *        Make sure we never have overlapping button gadgets (this might
  2330.      *        happen if we had a big gadget font and small buffer font).
  2331.      */
  2332.     buttonwidth = MaxTextLen(gfont, UseCancelUndoText) + 32;
  2333.     buttonspace = buttonwidth * 3 + FORM_MARGIN * 4 + BorderLeft + BorderRight;
  2334.  
  2335.     width = FBoxA_Width + FBoxB_Width + FORM_MARGIN * 4 +
  2336.                           BorderLeft  + BorderRight;
  2337.  
  2338.     outmargin = FORM_MARGIN;
  2339.     if (buttonspace > width)
  2340.         width = buttonspace;
  2341.  
  2342.     headingspace =    GetTextLen(gfont, MSG(MSG_AVAILABLE_GAD)) +
  2343.                     GetTextLen(gfont, MSG(MSG_CURFORMAT_GAD)) +
  2344.                     BorderLeft + BorderRight + FORM_MARGIN*3;
  2345.  
  2346.     if (headingspace > width)
  2347.         width = headingspace;
  2348.  
  2349.     /*
  2350.      *        Now calculate the dimensions of our two windows boxes. The left
  2351.      *        box displays the available format headings, and the right box
  2352.      *        displays the currently selected format headings.
  2353.      */
  2354.     FBoxSpacing        = bfonty + 2;
  2355.     FBoxA_Top        = topline + gfonty + 4;
  2356.     FBoxA_Height    = EF_COUNT * FBoxSpacing + 4;
  2357.     FBoxA_Left      = BorderLeft + outmargin;
  2358.  
  2359.     FBoxB_Top        = FBoxA_Top;
  2360.     FBoxB_Height    = FBoxA_Height;
  2361.     FBoxB_Left      = width - BorderRight - outmargin - FBoxB_Width;
  2362.      
  2363.     height = FBoxA_Top + FBoxA_Height + BorderBottom +
  2364.              (gfonty + GadgetHeight) * 3;
  2365.  
  2366.     if (width > ScreenWidth || height > ScreenHeight) {
  2367.         CloseFont(gfont);
  2368.         CloseFont(bfont);
  2369.         return (NULL);
  2370.     }
  2371.     if (getsize) {
  2372.         CloseFont(gfont);
  2373.         CloseFont(bfont);
  2374.         *pwidth  = width;
  2375.         *pheight = height;
  2376.         return (struct Gadget *)(-1);
  2377.     }
  2378.  
  2379.     /*
  2380.      *        Now create our window gadgets. We have a total of 4 -- the
  2381.      *        Use, Undo, Cancel buttons, and the field width slider.
  2382.      */    
  2383.     gadlist = NULL;
  2384.     gad = CreateContext(&gadlist);
  2385.     if (!gad)
  2386.         goto fogad_failed;
  2387.  
  2388.     ng.ng_TextAttr        = gadgetfa;
  2389.     ng.ng_VisualInfo    = FormVI;
  2390.     ng.ng_Flags            = PLACETEXT_IN;
  2391.     ng.ng_TopEdge          = height - BorderBottom - (gfonty+GadgetHeight) * 3/2;
  2392.     ng.ng_Height        = gfonty + GadgetHeight;
  2393.     ng.ng_Width            = buttonwidth;
  2394.  
  2395.     ng.ng_LeftEdge        = FORM_MARGIN + BorderLeft;
  2396.     ng.ng_GadgetText    = MSG(MSG_USE_GAD);
  2397.     ng.ng_GadgetID        = GID_FORMUSE;
  2398.  
  2399.     gad = CreateGadget(BUTTON_KIND,        gad, &ng,
  2400.                        GT_Underscore,    '_',
  2401.                        TAG_DONE);
  2402.     if (!gad)
  2403.         goto fogad_failed;
  2404.     Gadget[GID_FORMUSE] = gad;
  2405.     AddKeyShortcut(FormKeyboard, GID_FORMUSE, MSG_USE_GAD);
  2406.     
  2407.     ng.ng_LeftEdge        = width - BorderRight - FORM_MARGIN - ng.ng_Width;
  2408.     ng.ng_GadgetText    = MSG(MSG_CANCEL_GAD);
  2409.     ng.ng_GadgetID        = GID_FORMCANCEL;
  2410.  
  2411.     gad = CreateGadget(BUTTON_KIND,        gad, &ng,
  2412.                        GT_Underscore,    '_',
  2413.                        TAG_DONE);
  2414.     if (!gad)
  2415.         goto fogad_failed;
  2416.     Gadget[GID_FORMCANCEL] = gad;
  2417.     AddKeyShortcut(FormKeyboard, GID_FORMCANCEL, MSG_CANCEL_GAD);
  2418.     
  2419.     ng.ng_LeftEdge        = (ng.ng_LeftEdge + BorderLeft + FORM_MARGIN) / 2;
  2420.     ng.ng_GadgetText    = MSG(MSG_UNDO_GAD);
  2421.     ng.ng_GadgetID        = GID_FORMUNDO;
  2422.  
  2423.     gad = CreateGadget(BUTTON_KIND,        gad, &ng,
  2424.                        GT_Underscore,    '_',
  2425.                        TAG_DONE);
  2426.     if (!gad)
  2427.         goto fogad_failed;
  2428.     Gadget[GID_FORMUNDO] = gad;
  2429.     AddKeyShortcut(FormKeyboard, GID_FORMUNDO, MSG_UNDO_GAD);
  2430.  
  2431.     /*
  2432.      *        Create the slider gadget. We need to leave room on the left for
  2433.      *        the title, and on the right for the current value.
  2434.      */
  2435.     ng.ng_LeftEdge        = FORM_MARGIN + BorderLeft + 8 +
  2436.                           GetTextLen(gfont, MSG(MSG_FIELDWIDTH_GAD));
  2437.     ng.ng_Width            = width - FORM_MARGIN - ng.ng_LeftEdge -
  2438.                           BorderLeft - BorderRight - GetTextLen(gfont, "99 ");
  2439.     ng.ng_Height        = gfonty + 3;
  2440.     ng.ng_TopEdge         = (ng.ng_TopEdge + FBoxA_Top + FBoxA_Height -
  2441.                            ng.ng_Height) / 2;
  2442.     ng.ng_GadgetText    = MSG(MSG_FIELDWIDTH_GAD);
  2443.     ng.ng_GadgetID        = GID_FORMWIDTH;
  2444.     ng.ng_Flags            = PLACETEXT_LEFT;
  2445.  
  2446.     gad = CreateGadget(SLIDER_KIND,            gad, &ng,
  2447.                        GTSL_LevelFormat,    "%2ld ",
  2448.                        GTSL_LevelPlace,        PLACETEXT_RIGHT,
  2449.                        GTSL_Level,            1,
  2450.                        GTSL_Min,            1,
  2451.                        GTSL_Max,            MAX_FIELD_LEN,
  2452.                        GTSL_MaxLevelLen,    2,
  2453.                        GT_Underscore,        '_',
  2454.                        GA_Disabled,            TRUE,
  2455.                        GA_RelVerify,        TRUE,
  2456.                        TAG_DONE);
  2457.     if (!gad)
  2458.         goto fogad_failed;
  2459.     Gadget[GID_FORMWIDTH] = gad;
  2460.     AddKeyShortcut(FormKeyboard, GID_FORMWIDTH, MSG_FIELDWIDTH_GAD);
  2461.  
  2462.     FormGadFont = gfont;
  2463.     FormBufFont = bfont;
  2464.     return (gadlist);
  2465.  
  2466. fogad_failed:
  2467.     if (gadlist)
  2468.         FreeGadgets(gadlist);
  2469.     CloseFont(gfont);
  2470.     CloseFont(bfont);
  2471.     return (NULL);
  2472. }
  2473.  
  2474. /*
  2475.  *        ShowFormatLine(line, select)
  2476.  *
  2477.  *        Outputs the numbered line of text in the right-hand box. If the
  2478.  *        number given is too high, then a blank line is output instead.
  2479.  *        The text will be of the form "HeadingName.... %02x" according
  2480.  *        to the current contents of the line.
  2481.  *
  2482.  *        If select is FORMAT_SELECTED, the line will be highlighted, else
  2483.  *        it will be output normally.
  2484.  */
  2485. void ShowFormatLine(int line, int select)
  2486. {
  2487.     int bfontbaseline       = FormBufFont->tf_Baseline;
  2488.     int boxwidth             = FormBufFont->tf_XSize * FBoxB_NumChars;
  2489.     struct RastPort *rport = FormWindow->RPort;
  2490.     char viewbuf[60];
  2491.     int fillpen = 0;
  2492.     int textpen = 1;
  2493.     int textrow;
  2494.     
  2495.     if (select == FORMAT_SELECTED) {
  2496.         fillpen = ScreenDI->dri_Pens[FILLPEN];
  2497.         textpen = ScreenDI->dri_Pens[FILLTEXTPEN];
  2498.     }
  2499.     SetFont(rport, FormBufFont);
  2500.     SetAPen(rport, textpen);
  2501.     SetBPen(rport, fillpen);
  2502.     SetDrMd(rport, JAM2);
  2503.  
  2504.     if (line < 0 || line >= EF_COUNT)
  2505.         return;
  2506.  
  2507.     if (line < FBoxB_CurLines) {
  2508.         FieldInit *fi = &FieldTypes[CurrentFields[line].type];
  2509.  
  2510.         mysprintf(viewbuf, FBoxB_FormString, MSG(fi->titlemsgid),
  2511.                            CurrentFields[line].width, fi->idchar);
  2512.     } else {
  2513.         memset(viewbuf, ' ', FBoxB_NumChars);
  2514.     }
  2515.     textrow = FBoxB_Top + line*FBoxSpacing + 3;
  2516.     Move(rport, FBoxB_Left + 2, textrow + bfontbaseline);
  2517.     Text(rport, viewbuf, FBoxB_NumChars);
  2518.  
  2519.     /*
  2520.      *        Now draw highlight on top and bottom of selected line
  2521.      *        (or erase, as the case may be). This fills out the
  2522.      *        selection area and makes it look much better.
  2523.      */
  2524.     SetAPen(rport, fillpen);
  2525.     Move(rport, FBoxB_Left + 2, textrow - 1);
  2526.     Draw(rport, FBoxB_Left + 1 + boxwidth, textrow - 1);
  2527.     Move(rport, FBoxB_Left + 2, textrow + FormBufFont->tf_YSize);
  2528.     Draw(rport, FBoxB_Left + 1 + boxwidth, textrow + FormBufFont->tf_YSize);
  2529. }
  2530.  
  2531. /*
  2532.  *        ShowDragSelect(pos, select)
  2533.  *
  2534.  *        Highlights the specified region to indicate where the currently
  2535.  *        dragged field will end up if it is released here.
  2536.  *
  2537.  *        If pos is FBOX_NOSELECT, no drop area is active and no output is
  2538.  *        produced. If pos is FBOX_SELECTLEFT, then the left box is active
  2539.  *        and it is given an inverse highlight around the interior of the
  2540.  *        box giving a bezel effect.
  2541.  *
  2542.  *        If pos is in the range 0 ... EF_COUNT, then it corresponds to an
  2543.  *        insertion point between two lines in the right-most box. This is
  2544.  *        show by a two-pixel high highlight line drawn between those two
  2545.  *        lines.
  2546.  *
  2547.  *        If select is FORMAT_SELECTED, the feature is drawn; if select is
  2548.  *        FORMAT_UNSELECTED, the feature is instead erased. Note that after
  2549.  *        calling this function, it may be necessary to redisplay any
  2550.  *        current highlight bar in the right box (see ShowFormatLine) since
  2551.  *        there is a one-pixel overlap between the highlight bar and the
  2552.  *        rendering done here.
  2553.  */
  2554. void ShowDragSelect(int pos, int select)
  2555. {
  2556.     struct RastPort *rport = FormWindow->RPort;
  2557.     int black = 1;
  2558.     int white = 2; 
  2559.  
  2560.     if (pos == FBOX_NOSELECT)
  2561.         return;
  2562.     
  2563.     if (select == FORMAT_UNSELECTED) {
  2564.         black = 0;
  2565.         white = 0;
  2566.     }
  2567.     SetDrMd(rport, JAM2);
  2568.     if (pos == FBOX_SELECTLEFT) {
  2569.         /*
  2570.          *        Draw bezel inside left box
  2571.          */
  2572.         int boxleft  = FBoxA_Left + 2;
  2573.         int boxtop     = FBoxA_Top  + 1;
  2574.         int boxright = FBoxA_Left + FBoxA_Width  - 3;
  2575.         int boxbot   = FBoxA_Top  + FBoxA_Height - 2;
  2576.  
  2577.         SetAPen(rport, black);
  2578.         Move(rport, boxleft,    boxbot);
  2579.         Draw(rport, boxleft,    boxtop);
  2580.         Move(rport, boxleft+1,    boxbot-1);
  2581.         Draw(rport, boxleft+1,    boxtop);
  2582.         Draw(rport, boxright-1,    boxtop);
  2583.  
  2584.         SetAPen(rport, white);
  2585.         Move(rport, boxright,    boxtop);
  2586.         Draw(rport, boxright,    boxbot);
  2587.         Move(rport, boxright-1,    boxtop);
  2588.         Draw(rport, boxright-1,    boxbot);
  2589.         Draw(rport, boxleft-1,    boxbot);
  2590.     } else if (pos >= 0 && pos <= EF_COUNT) {
  2591.         /*
  2592.          *        Draw thin selection line in right box
  2593.          */
  2594.         int line = FBoxB_Top + 1 + pos * FBoxSpacing;
  2595.  
  2596.         SetAPen(rport, white);
  2597.         Move(rport, FBoxB_Left+2,                line);
  2598.         Draw(rport, FBoxB_Left+FBoxB_Width-3,    line);
  2599.         SetAPen(rport, black);
  2600.         Move(rport, FBoxB_Left+2,                line+1);
  2601.         Draw(rport, FBoxB_Left+FBoxB_Width-3,    line+1);
  2602.     }
  2603. }
  2604.  
  2605. /*
  2606.  *        RedrawFormatWindow()
  2607.  *
  2608.  *        Redraws all the parts of the format window that are generated by
  2609.  *        hand: this includes the two bevelled boxes containing the available
  2610.  *        format fields, the headings for those boxes, and the current contens
  2611.  *        of those boxes, including highlighting where appropriate.
  2612.  */
  2613. void RedrawFormatWindow(void)
  2614. {
  2615.     char viewbuf[60];
  2616.     struct RastPort *rport = FormWindow->RPort;
  2617.     int gfonty          = FormGadFont->tf_YSize;
  2618.     int gfontbaseline = FormGadFont->tf_Baseline;
  2619.     int bfontbaseline = FormBufFont->tf_Baseline;
  2620.     int line;
  2621.     int headpos;
  2622.     EditEvent *ee;
  2623.  
  2624.     DrawBevelBox(rport, FBoxA_Left, FBoxA_Top, FBoxA_Width, FBoxA_Height,
  2625.                         GT_VisualInfo, FormVI,
  2626.                         TAG_DONE);
  2627.  
  2628.     DrawBevelBox(rport, FBoxB_Left, FBoxB_Top, FBoxB_Width, FBoxB_Height,
  2629.                         GT_VisualInfo, FormVI,
  2630.                         TAG_DONE);
  2631.  
  2632.     SetAPen(rport, 1);
  2633.     SetBPen(rport, 0);
  2634.     SetDrMd(rport, JAM2);
  2635.     SetFont(rport, FormGadFont);
  2636.  
  2637.     /*
  2638.      *        When outputting the box headings, we adjust the centering
  2639.      *        to ensure that headings wider than the boxes don't get
  2640.      *        pushed into the window borders.
  2641.      */
  2642. #define CENTRE(left,width,msgid)    \
  2643.             ((width - GetTextLen(FormGadFont, MSG(msgid)))/2 + left)
  2644.  
  2645.     headpos = CENTRE(FBoxA_Left, FBoxA_Width, MSG_AVAILABLE_GAD);
  2646.     if (headpos < (BorderLeft + 4))
  2647.         headpos = FBoxA_Left; /* was: BorderLeft + 4; */
  2648.  
  2649.     Move(rport, headpos, FBoxA_Top - gfonty + gfontbaseline - 4);
  2650.     Text(rport, MSG(MSG_AVAILABLE_GAD), strlen(MSG(MSG_AVAILABLE_GAD)));
  2651.  
  2652.     headpos = CENTRE(FBoxB_Left, FBoxB_Width, MSG_CURFORMAT_GAD);
  2653.     if (headpos < (FBoxB_Left - 4))
  2654.         headpos = FBoxB_Left + FBoxB_Width -
  2655.                                GetTextLen(FormGadFont, MSG(MSG_CURFORMAT_GAD));
  2656.  
  2657.     Move(rport, headpos, FBoxB_Top - gfonty + gfontbaseline - 4);
  2658.     Text(rport, MSG(MSG_CURFORMAT_GAD), strlen(MSG(MSG_CURFORMAT_GAD)));
  2659.  
  2660.     /*
  2661.      *        Now redraw the text inside the left box (available headings)
  2662.      */
  2663.     SetFont(rport, FormBufFont);
  2664.     ee = &AvailableFields[0];
  2665.     for (line = 0; line < (FBoxB_Height - 4); line += FBoxSpacing) {
  2666.         if (ee->type != END_EDITLIST) {
  2667.             FieldInit *fi = &FieldTypes[ee->type];
  2668.             mysprintf(viewbuf, FBoxA_FormString, MSG(fi->titlemsgid),
  2669.                                                     fi->idchar);
  2670.             ee++;
  2671.         } else {
  2672.             memset(viewbuf, ' ', FBoxA_NumChars);
  2673.         }
  2674.         Move(rport, FBoxA_Left + 2, FBoxA_Top + line + bfontbaseline + 3);
  2675.         Text(rport, viewbuf, FBoxA_NumChars);
  2676.     }
  2677.  
  2678.     /*
  2679.      *        Redraw the text inside the right box (currently selected headings)
  2680.      */
  2681.     ee = &CurrentFields[0];
  2682.     for (line = 0; line < EF_COUNT; line++) {
  2683.         if (line == FBoxSelected)
  2684.             ShowFormatLine(line, FORMAT_SELECTED);
  2685.         else
  2686.             ShowFormatLine(line, FORMAT_UNSELECTED);
  2687.     }
  2688. }
  2689.  
  2690. /*
  2691.  *        ConvertListToFormat(list, format)
  2692.  *
  2693.  *        Converts the passed in EditList to a format list which can be
  2694.  *        used for updating the main SnoopDos display. Returns the
  2695.  *        total width (in characters) occupied by the format.
  2696.  */
  2697. int ConvertListToFormat(EditEvent *ee, EventFormat *evformat)
  2698. {
  2699.     int width = 0;
  2700.  
  2701.     while (ee->type != END_EDITLIST) {
  2702.         width               += ee->width + 1; /* Include space between cols */
  2703.         evformat->type         = FieldTypes[ee->type].type;
  2704.         evformat->width         = ee->width;
  2705.         evformat->titlemsgid = FieldTypes[ee->type].titlemsgid;
  2706.         evformat++;
  2707.         ee++;
  2708.     }
  2709.     evformat->type = EF_END;
  2710.     if (width)
  2711.         width--;        /* Don't count extra space at end */
  2712.     return (width);
  2713. }
  2714.  
  2715. /*
  2716.  *        CreateFormatLists(format)
  2717.  *
  2718.  *        Parses the passed-in format string and creates the two lists
  2719.  *        used by the format editor window to allow the user to re-arrange
  2720.  *        the format.
  2721.  *
  2722.  *        Should be called before RedrawFormatWindow() is called for the
  2723.  *        first time.
  2724.  *
  2725.  *        Also initialises some format globals related to the list boxes.
  2726.  */
  2727. void CreateFormatLists(EventFormat *evformat)
  2728. {
  2729.     EditEvent *ee;
  2730.     FieldInit *fi;
  2731.     EventFormat *ef;
  2732.  
  2733.     /*
  2734.      *        Now build the lists for the two boxes. The right box contains
  2735.      *        all items in the format string (and in the same order that they
  2736.      *        appear in the format string). The left box contains all the
  2737.      *        items that are NOT in the format string, in the presorted
  2738.      *        order that they appear in the FieldTypes[] initialiser array.
  2739.      *
  2740.      *        Note that the two edit lists contain indexes directly into
  2741.      *        the FieldTypes array, rather than specific event types.
  2742.      *        Thus, we store the offset into the array when we find a match
  2743.      *        rather than fi->type.
  2744.      */
  2745.     ee = &CurrentFields[0];
  2746.     for (ef = evformat; ef->type != EF_END; ef++) {
  2747.         for (fi = FieldTypes; fi->type != ef->type && fi->type != EF_END; fi++)
  2748.             ;
  2749.         ee->type  = fi - FieldTypes;
  2750.         ee->width = ef->width;
  2751.         ee++;
  2752.     }
  2753.     ee->type = END_EDITLIST;
  2754.     FBoxB_CurLines = ee - &CurrentFields[0];
  2755.  
  2756.     ee = &AvailableFields[0];
  2757.     for (fi = FieldTypes; fi->type != EF_END; fi++) {
  2758.         for (ef = BufferEFormat; ef->type != fi->type && ef->type != EF_END;
  2759.                                 ef++)
  2760.             ;
  2761.         if (ef->type != fi->type) {    /* Not in current format so add it here */
  2762.             ee->type = fi - &FieldTypes[0];
  2763.             ee++;
  2764.         }
  2765.     }
  2766.     ee->type = END_EDITLIST;
  2767.  
  2768.     FBoxA_CurLines        = ee - &AvailableFields[0];
  2769.     FBoxSelected        = FBOX_NOSELECT;
  2770.     FBoxDragSelect        = FBOX_NOSELECT;
  2771.     FormatCurLMB        = 0;    /* Left mouse button not selected at start */
  2772.     FormatMovingField    = 0;
  2773.     /*
  2774.      *        Ensure slider gadget is disabled (it might have been left
  2775.      *        enabled from an earlier time, which can be confusing).
  2776.      */
  2777.     if (FormWindow) {
  2778.         GT_SetGadgetAttrs(Gadget[GID_FORMWIDTH], FormWindow,  NULL,
  2779.                           GA_Disabled, TRUE,
  2780.                           TAG_DONE);
  2781.     }
  2782. }
  2783.  
  2784. /*
  2785.  *        OpenFormatWindow()
  2786.  *
  2787.  *        Opens the format editor window with all the format gadgets.
  2788.  *        Returns TRUE for success, FALSE for failure.
  2789.  *        The window will contain all necessary gadgets.
  2790.  *
  2791.  *        As with the Settings window, we try a variety of fonts until we
  2792.  *        find one that fits onto the screen.
  2793.  */
  2794. int OpenFormatWindow(void)
  2795. {
  2796.     static struct TextAttr formgfontattr =
  2797.         { "empty-storage-for-format1-fonts", 0, FS_NORMAL, FPB_DISKFONT};
  2798.     static struct TextAttr formbfontattr =
  2799.         { "empty-storage-for-format2-fonts", 0, FS_NORMAL, FPB_DISKFONT};
  2800.  
  2801.     static int width;        /* Maintained from call to call */
  2802.     static int height;
  2803.  
  2804.     int left = CurSettings.FormWinLeft;
  2805.     int top  = CurSettings.FormWinTop;
  2806.     struct TextAttr *gadgetfa;
  2807.     struct TextAttr *bufferfa;
  2808.     struct Window *win;
  2809.     int i;
  2810.  
  2811.     CheckSegTracker();
  2812.     if (FormWindow) {
  2813.         WindowToFront(FormWindow);
  2814.         ActivateWindow(FormWindow);
  2815.         return (TRUE);
  2816.     }
  2817.     if (!CheckForScreen())
  2818.         return (FALSE);
  2819.  
  2820.     strcpy(FormatSaveFormat, BufFormat);    /* Save for possible Undo */
  2821.  
  2822.     /*
  2823.      *        Now try all combinations of gadget and buffer font until we
  2824.      *        find a font combination that fits on our screen
  2825.      */
  2826.     for (i = 0; gadgetfa = MainWindowFontList[i].gadgetfa; i++) {
  2827.         bufferfa = MainWindowFontList[i].bufferfa;
  2828.         if (CreateFormatGadgets(gadgetfa, bufferfa, TRUE, &width, &height))
  2829.             break;
  2830.     }
  2831.     if (!gadgetfa) {
  2832.         ShowError(MSG(MSG_ERROR_OPENFORMAT));
  2833.         return (FALSE);
  2834.     }
  2835.     /*
  2836.      *        Now copy our font attributes so that our gadgets won't strangely
  2837.      *        get changed behind the scenes if we update our fonts
  2838.      */
  2839.     strcpy(formgfontattr.ta_Name, gadgetfa->ta_Name);
  2840.     formgfontattr.ta_YSize = gadgetfa->ta_YSize;
  2841.     gadgetfa = &formgfontattr;
  2842.  
  2843.     strcpy(formbfontattr.ta_Name, bufferfa->ta_Name);
  2844.     formbfontattr.ta_YSize = bufferfa->ta_YSize;
  2845.     bufferfa = &formbfontattr;
  2846.  
  2847.     if (left == -1)  left = (ScreenWidth  - width)  / 2;
  2848.     if (top  == -1)  top  = (ScreenHeight - height) / 2;
  2849.  
  2850.     win = OpenWindowTags(NULL,
  2851.                          WA_Title,            MSG(MSG_FORMAT_TITLE),
  2852.                          WA_IDCMP,            IDCMP_CLOSEWINDOW     |
  2853.                                             IDCMP_REFRESHWINDOW     |
  2854.                                             IDCMP_NEWSIZE         |
  2855.                                             IDCMP_RAWKEY         |
  2856.                                             IDCMP_MOUSEBUTTONS     |
  2857.                                             IDCMP_INACTIVEWINDOW |
  2858.                                             BUTTONIDCMP             |
  2859.                                             SLIDERIDCMP,
  2860.                          WA_Left,              left,
  2861.                          WA_Top,              top,
  2862.                          WA_Width,            width,
  2863.                          WA_Height,            height,
  2864.                          WA_Flags,            WFLG_DRAGBAR         |
  2865.                                              WFLG_DEPTHGADGET     |
  2866.                                             WFLG_ACTIVATE         |
  2867.                                             WFLG_RMBTRAP         |
  2868.                                             WFLG_NEWLOOKMENUS,
  2869.                          RefreshTag,          TRUE,
  2870.                          WA_NoCareRefresh,    NoCareRefreshBool,
  2871.                          WA_PubScreen,        SnoopScreen,
  2872.                          TAG_DONE);
  2873.     if (!win) {
  2874.         ShowError(MSG(MSG_ERROR_OPENFORMAT));
  2875.         return (FALSE);
  2876.     }
  2877.  
  2878.     if (!FormGadList) {
  2879.         FormGadList = CreateFormatGadgets(gadgetfa, bufferfa, 0, 0, 0);
  2880.         if (!FormGadList) {
  2881.             CloseWindow(win);
  2882.             ShowError(MSG(MSG_ERROR_OPENFORMAT));
  2883.             return (FALSE);
  2884.         }
  2885.     }
  2886.  
  2887.     /*
  2888.      *        Now try and create our BOBs for the window
  2889.      */
  2890.     TextBob = CreateBob(win->RPort, FBoxB_Width + 8,
  2891.                                     FormBufFont->tf_YSize + 4, 1);
  2892.     if (!TextBob) {
  2893.         ShowError(MSG(MSG_ERROR_OPENFORMAT));
  2894.         FreeGadgets(FormGadList);
  2895.         FormGadList    = NULL;
  2896.         CloseWindow(win);
  2897.         return (FALSE);
  2898.     }
  2899.     AddBob(&TextBob->bob, win->RPort);
  2900.  
  2901.     /*
  2902.      *        Now add gadgets to screen window, and then setup the current
  2903.      *        format string for editing.
  2904.      */
  2905.     AddGList(win, FormGadList, -1, -1, NULL);
  2906.     RefreshGList(FormGadList, win, NULL, -1);
  2907.     GT_RefreshWindow(win, NULL);
  2908.  
  2909.     /*
  2910.      *        All done, so initialise some globals and return
  2911.      */
  2912.     FormWindow        = win;
  2913.     FormWindowPort    = win->UserPort;
  2914.     FormWindowMask    = 1 << FormWindowPort->mp_SigBit;
  2915.  
  2916.     CreateFormatLists(BufferEFormat);
  2917.     /*
  2918.      *        Finally, draw our window to reflect this
  2919.      */
  2920.     RedrawFormatWindow();
  2921.     if (DisableNestCount)
  2922.         DisableWindow(FormWindow, &FormRequester);
  2923.     return (TRUE);
  2924. }
  2925.  
  2926. /*
  2927.  *        CloseFormatWindow(void)
  2928.  *
  2929.  *        Close the format window and free gadgets associated with the window.
  2930.  */
  2931. void CloseFormatWindow(void)
  2932. {
  2933.     if (FormWindow) {
  2934.         if (TextBob) {
  2935.             FreeBob(TextBob);
  2936.             TextBob = NULL;
  2937.         }
  2938.         RecordWindowSizes();
  2939.         CloseWindow(FormWindow);
  2940.         CloseFont(FormGadFont);
  2941.         CloseFont(FormBufFont);
  2942.         FormWindow     = NULL;
  2943.         FormWindowMask = 0;
  2944.         FormGadFont       = NULL;
  2945.         FormBufFont       = NULL;
  2946.     }
  2947.     if (FormGadList) {
  2948.         FreeGadgets(FormGadList);
  2949.         FormGadList = NULL;
  2950.     }
  2951.     if (FormVI) {
  2952.         FreeVisualInfo(FormVI);
  2953.         FormVI = NULL;
  2954.     }
  2955. }
  2956.  
  2957. /*
  2958.  *        FormatHitDetect(x, y)
  2959.  *
  2960.  *        Does a bounds check for the specified X/Y co-ordinates against the
  2961.  *        format editor window. A return value in the range 0..EF_COUNT-1
  2962.  *        indicates that line number in the right hand window was hit.
  2963.  *
  2964.  *        A return of FBOX_SELECTLEFT indicates that the left box was selected
  2965.  *        (not sure which line; doesn't really matter).
  2966.  *
  2967.  *        A return of FBOX_NOSELECT indicates neither box was selected.
  2968.  */
  2969. int FormatHitDetect(int x, int y)
  2970. {
  2971.     if (x >= FBoxA_Left && x <= (FBoxA_Left + FBoxA_Width  - 1) &&
  2972.         y >= FBoxA_Top  && y <= (FBoxA_Top  + FBoxA_Height - 1))
  2973.     {
  2974.         return (FBOX_SELECTLEFT);
  2975.     }
  2976.     
  2977.     if (x >= FBoxB_Left && x <= (FBoxB_Left + FBoxB_Width  - 1) &&
  2978.         y >= FBoxB_Top  && y <= (FBoxB_Top  + FBoxB_Height - 1))
  2979.     {
  2980.         if (y <= FBoxB_Top + FBoxSpacing + 2)
  2981.             return (0);
  2982.         else
  2983.             return (y - FBoxB_Top - 2) / FBoxSpacing;
  2984.     }
  2985.     return (FBOX_NOSELECT);
  2986. }
  2987.  
  2988. /*
  2989.  *        InstallNewFormat(type)
  2990.  *
  2991.  *        Installs the currently defined format into the main window for
  2992.  *        the user to see immediately.
  2993.  *
  2994.  *        If type is NEW_LISTVIEW, then the new format is assumed to be
  2995.  *        from the format editor window's CurrentFields list. The
  2996.  *        setup window, if open, will have its own format string updated
  2997.  *        accordingly.
  2998.  *
  2999.  *        If type is NEW_STRING, then the new format is assumed to be
  3000.  *        stored in the BufFormat string. The format window, if open,
  3001.  *        will have its own format listview updated accordingly.
  3002.  *
  3003.  *        If the buffer string is completely invalid (i.e. evaluates to
  3004.  *        an empty format) then it will be replaced with an empty string.
  3005.  */
  3006. void InstallNewFormat(int type)
  3007. {
  3008.     if (type == NEW_LISTVIEW) {
  3009.         BufferWidth = ConvertListToFormat(CurrentFields, BufferEFormat);
  3010.     } else /* type == NEW_STRING */ {
  3011.         BufferWidth = ParseFormatString(BufFormat, BufferEFormat,
  3012.                                                    MAX_FORM_LEN);
  3013.         if (BufferWidth == 0) {
  3014.             BufferWidth = ParseFormatString(DefaultSettings.Setup.BufferFormat,
  3015.                                             BufferEFormat, MAX_FORM_LEN);
  3016.         }
  3017.         if (FormWindow) {
  3018.             CreateFormatLists(BufferEFormat);
  3019.             RedrawFormatWindow();
  3020.         }
  3021.     }
  3022.     BuildFormatString(BufferEFormat, BufFormat, MAX_FORM_LEN);
  3023.     if (SetWindow) {
  3024.         GT_SetGadgetAttrs(Gadget[GID_BUFFORMAT], SetWindow, NULL,
  3025.                           GTST_String,    BufFormat,
  3026.                           TAG_DONE);
  3027.     }
  3028.     ClearMainRHS = 1;
  3029.     InitMainMargins();
  3030.     UpdateMainHScroll();
  3031.     RedrawMainWindow();
  3032. }
  3033.  
  3034. /*
  3035.  *        HandleFormatMsgs()
  3036.  *
  3037.  *        Processes all outstanding messages associated with the Format
  3038.  *        editor gadget window. To be called whenever we get a format event.
  3039.  */
  3040. void HandleFormatMsgs(void)
  3041. {
  3042.     static int activegad;            /* Non-zero if gadget is depressed   */
  3043.     static int activekey;            /* Keycode shortcut of activegad     */
  3044.  
  3045.     struct IntuiMessage *imsg;
  3046.     int doneform = SEL_NONE;
  3047.     int hit;
  3048.     int lmb;
  3049.     int rmb;
  3050.  
  3051.     if (!FormWindow)
  3052.         return;
  3053.  
  3054.     while ((imsg = GT_GetIMsg(FormWindowPort)) != NULL) {
  3055.         struct Gadget *gad;
  3056.         int dxwidth = 0;                /* Amount to adjust width by */
  3057.         int newrow  = FBoxSelected;        /* Currently selected row     */
  3058.         int gadid;
  3059.  
  3060.         switch (imsg->Class) {
  3061.             
  3062.             case IDCMP_CLOSEWINDOW:
  3063.                 doneform = SEL_USE;
  3064.                 break;
  3065.  
  3066.             case IDCMP_REFRESHWINDOW:
  3067.                 GT_BeginRefresh(FormWindow);
  3068.                 RedrawFormatWindow();
  3069.                 GT_EndRefresh(FormWindow, TRUE);
  3070.                 break;
  3071.  
  3072.             case IDCMP_MOUSEBUTTONS:
  3073.                 lmb = imsg->Qualifier & IEQUALIFIER_LEFTBUTTON;
  3074.                 rmb = imsg->Qualifier & IEQUALIFIER_RBUTTON;
  3075.                 /*
  3076.                  *        If we're already dragging something, then the
  3077.                  *        right mouse button allows it to be cancelled.
  3078.                  */
  3079.                 if (FormatMovingField && rmb)
  3080.                     goto cancel_moving_field;
  3081.  
  3082.                 if (lmb == FormatCurLMB)    /* Ignore spurious events */
  3083.                     break;
  3084.  
  3085.                 hit = FormatHitDetect(imsg->MouseX, imsg->MouseY);
  3086.                 if (lmb) {
  3087.                     /*
  3088.                      *        User is trying to select or pick-up a new
  3089.                      *        event.
  3090.                      */
  3091.                     if (hit >= 0 && hit < FBoxB_CurLines &&
  3092.                                                 hit != FBoxSelected) {
  3093.                         if (FBoxSelected >= 0 && FBoxSelected < FBoxB_CurLines)
  3094.                             ShowFormatLine(FBoxSelected, FORMAT_UNSELECTED);
  3095.                         FBoxSelected = hit;
  3096.                         ShowFormatLine(hit, FORMAT_SELECTED);
  3097.                         GT_SetGadgetAttrs(Gadget[GID_FORMWIDTH],
  3098.                                           FormWindow,  NULL,
  3099.                                           GA_Disabled, FALSE,
  3100.                                           GTSL_Level, CurrentFields[hit].width,
  3101.                                           TAG_DONE);
  3102.                     }
  3103.                     if (hit != FBOX_NOSELECT) {
  3104.                         /*
  3105.                          *        Pick-up the icon under mouse
  3106.                          */
  3107.                         if (PickupBob(hit, imsg->MouseX, imsg->MouseY)) {
  3108.                             FormatMovingField = 1;
  3109.                             ReportMouse(1, FormWindow);    /* Enable mouse moves */
  3110.                         }
  3111.                     }
  3112.                 } else {
  3113.                     /*
  3114.                      *        We might be finished doing a drag of a field
  3115.                      *        from one position to another -- if so, drop the
  3116.                      *        field in it's new place.
  3117.                      */
  3118.                     if (FormatMovingField) {
  3119.                         int curdragselect = FBoxDragSelect;
  3120.  
  3121.                         FormatMovingField = 0;
  3122.                         ReportMouse(0, FormWindow);    /* Disable mouse moves  */
  3123.                         DropBob();
  3124.                         if (curdragselect != FBOX_NOSELECT)
  3125.                             InstallNewFormat(NEW_LISTVIEW);
  3126.                     }
  3127.                 }
  3128.                 FormatCurLMB = lmb;
  3129.                 break;
  3130.                         
  3131.             case IDCMP_MOUSEMOVE: 
  3132.                 if (FormatMovingField) {
  3133.                     UpdateBob(imsg->MouseX, imsg->MouseY);
  3134.                     break;
  3135.                 }
  3136.  
  3137.                 /*
  3138.                  *        Fall through to handle MOUSEMOVE for slider gadget
  3139.                  */
  3140.  
  3141.             case IDCMP_GADGETDOWN:
  3142.             case IDCMP_GADGETUP:
  3143.                 gad   = (struct Gadget *)imsg->IAddress;
  3144.                 gadid = gad->GadgetID;
  3145.  
  3146. handle_form_gads:
  3147.                 switch (gadid) {
  3148.  
  3149.                     case GID_FORMUSE:
  3150.                         doneform = SEL_USE;
  3151.                         break;
  3152.  
  3153.                     case GID_FORMCANCEL:
  3154.                         doneform = SEL_CANCEL;
  3155.                         break;
  3156.  
  3157.                     case GID_FORMUNDO:
  3158.                         strcpy(BufFormat, FormatSaveFormat);
  3159.                         InstallNewFormat(NEW_STRING);
  3160.                         break;
  3161.  
  3162.                     case GID_FORMWIDTH:
  3163.                         /*
  3164.                           *        The slider has been moved, so update the
  3165.                           *        currently selected item accordingly.
  3166.                           */
  3167.                         if (FBoxSelected >= 0 &&
  3168.                                             FBoxSelected < FBoxB_CurLines) {
  3169.                             CurrentFields[FBoxSelected].width = imsg->Code;
  3170.                             ShowFormatLine(FBoxSelected, FORMAT_SELECTED);
  3171.                             if (imsg->Class == IDCMP_GADGETUP)
  3172.                                 InstallNewFormat(NEW_LISTVIEW);
  3173.                         }
  3174.                         break;
  3175.                 }
  3176.                 break;
  3177.  
  3178.             case IDCMP_INACTIVEWINDOW:
  3179.                 /*
  3180.                  *        Cancel any currently pressed button
  3181.                  */
  3182.                 if (activegad) {
  3183.                     ShowGadget(FormWindow, Gadget[activegad], GADGET_UP);
  3184.                     activegad = 0;
  3185.                 }
  3186.                 /*
  3187.                  *        If we're dragging something and the window
  3188.                  *        goes inactive, drop it. Otherwise, when the
  3189.                  *        window is reactivated, it will still be attached
  3190.                  *        to the mouse pointer!
  3191.                  */
  3192.                 if (FormatMovingField) {
  3193.                     FormatCurLMB      = 0;
  3194. cancel_moving_field:
  3195.                     ReportMouse(0, FormWindow);
  3196.                     UpdateBob(0, -9999);        /* Make position invalid */
  3197.                     DropBob();
  3198.                     FormatMovingField = 0;
  3199.                     if (imsg->Class == IDCMP_INACTIVEWINDOW) {
  3200.                         /*
  3201.                          *        If we went inactive, then the act of
  3202.                          *        erasing the BOB has probably resulted
  3203.                          *        in a portion of the window frame being
  3204.                          *        restored in its active colours, even
  3205.                          *        though the window is now inactive -- so
  3206.                          *        we refresh it to get around this.
  3207.                          */
  3208.                         RefreshWindowFrame(FormWindow);
  3209.                     }
  3210.                 }
  3211.                 break;
  3212.                     
  3213.             case IDCMP_RAWKEY:
  3214.             {
  3215.                 int shift    = imsg->Qualifier & IE_SHIFT;
  3216.                 int altctrl  = imsg->Qualifier & (IE_ALT | IE_CTRL);
  3217.                 int upstroke = imsg->Code & 0x80;
  3218.                 int keypress = ConvertIMsgToChar(imsg);
  3219.  
  3220.                 /*
  3221.                  *        Handle keyboard shortcuts
  3222.                  */
  3223.                 if (FormatMovingField && keypress == '\033') {
  3224.                     /*
  3225.                      *        ESC cancels any drag currently in operation
  3226.                      */
  3227.                     goto cancel_moving_field;
  3228.                 }
  3229.  
  3230.                 gadid  = FormKeyboard[keypress];
  3231.                 if (activegad) {
  3232.                     /*
  3233.                      *        We're releasing a gadget that was pressed
  3234.                      *        earlier, so handle it now
  3235.                      */
  3236.                     int samekey = (imsg->Code & 0x7f) == activekey;
  3237.  
  3238.                     if (samekey && !upstroke)    /* Ignore repeated keys */
  3239.                         break;
  3240.  
  3241.                     ShowGadget(FormWindow, Gadget[activegad], GADGET_UP);
  3242.                     if (samekey) {
  3243.                         /*
  3244.                          *        Just released the key that was originally
  3245.                          *        pressed for this gadget, so now go and
  3246.                          *        handle the gadget action.
  3247.                          */
  3248.                         gadid     = activegad;
  3249.                         gad       = Gadget[gadid];
  3250.                         activegad = 0;
  3251.                         goto handle_form_gads;
  3252.                     }
  3253.  
  3254.                     /*
  3255.                      *        If the above check didn't kick in, it means
  3256.                      *        we got a downpress of a different key, so
  3257.                      *        disable the gadget for this key and continue
  3258.                      *        to press the other key.
  3259.                      */
  3260.                     activegad = 0;
  3261.                 }
  3262.  
  3263.                 /*
  3264.                  *        Check for normal gadget keyboard shortcuts
  3265.                  */
  3266.                 if (gadid) {
  3267.                     gad = Gadget[gadid];
  3268.                     if (gadid == GID_FORMWIDTH) {
  3269.                         /*
  3270.                          *        Got a slider adjustment request
  3271.                          */
  3272.                         if (imsg->Qualifier & IE_SHIFT)
  3273.                             dxwidth = -1;
  3274.                         else
  3275.                             dxwidth = 1;
  3276.  
  3277.                         if (newrow == FBOX_NOSELECT)
  3278.                             newrow = 0;    /* If no row active, pick first row */
  3279.  
  3280.                         if (FBoxB_CurLines == 0)  /* Ignore if box is empty */
  3281.                             break;
  3282.  
  3283.                         goto format_move_slider;
  3284.                     }
  3285.                     /*
  3286.                      *        Must be a simple button press so highlight
  3287.                      *        the button and handle accordingly
  3288.                      */
  3289.                     ShowGadget(FormWindow, gad, GADGET_DOWN);
  3290.                     activegad = gadid;
  3291.                     activekey = imsg->Code;
  3292.                     break;
  3293.                 }
  3294.  
  3295.                 /*
  3296.                  *        Handle cursor movement. This lets us choose a
  3297.                  *        new item in the format box, or adjust the width
  3298.                  *        of an existing item.
  3299.                  */
  3300.                 if (!FBoxB_CurLines)    /* A format must exist */
  3301.                     break;
  3302.                 
  3303.                 if (newrow == FBOX_NOSELECT)
  3304.                     newrow = -1;    /* Ensure cursor down selects item 0 */
  3305.  
  3306.                 switch (imsg->Code) {
  3307.                     case CURSORUP:
  3308.                         if (newrow > 0 && !(shift | altctrl))
  3309.                             newrow--;
  3310.                         else
  3311.                             newrow = 0;
  3312.                         break;
  3313.  
  3314.                     case CURSORDOWN:
  3315.                         if (shift | altctrl)
  3316.                             newrow = FBoxB_CurLines - 1;
  3317.                         else if (newrow < (FBoxB_CurLines-1))
  3318.                             newrow++;
  3319.                         break;
  3320.  
  3321.                     case CURSORLEFT:
  3322.                         dxwidth = -1;
  3323.                         if (shift)   dxwidth  = -5;
  3324.                         if (altctrl) dxwidth  = -MAX_FIELD_LEN;
  3325.                         break;
  3326.  
  3327.                     case CURSORRIGHT:
  3328.                         dxwidth = 1;
  3329.                         if (shift)   dxwidth = 5;
  3330.                         if (altctrl) dxwidth = MAX_FIELD_LEN;
  3331.                         break;
  3332.  
  3333.                     case HELPKEY:
  3334.                         ShowAGuide(MSG(MSG_LINK_FORMATWIN));
  3335.                         goto done_keys;
  3336.  
  3337.                     default:
  3338.                         goto done_keys;        /* Ignore all other keys */
  3339.                 }
  3340.  
  3341. format_move_slider:
  3342.                 /*
  3343.                  *        First check if the row has changed. (As well as
  3344.                  *        changing via cursor up/down, this can also happen
  3345.                  *        with left/right if there was no item selected to
  3346.                  *        begin with
  3347.                  */
  3348.                 if (newrow < 0)
  3349.                     newrow = 0;
  3350.  
  3351.                 if (newrow != FBoxSelected && FBoxB_CurLines > 0) {
  3352.                     /*
  3353.                      *        Unactivate old row, activate a new row
  3354.                      */
  3355.                     if (FBoxSelected >= 0 && FBoxSelected < FBoxB_CurLines)
  3356.                         ShowFormatLine(FBoxSelected, FORMAT_UNSELECTED);
  3357.                     FBoxSelected = newrow;
  3358.                     ShowFormatLine(newrow, FORMAT_SELECTED);
  3359.                     GT_SetGadgetAttrs(Gadget[GID_FORMWIDTH],
  3360.                                       FormWindow,  NULL,
  3361.                                       GA_Disabled, FALSE,
  3362.                                       GTSL_Level, CurrentFields[newrow].width,
  3363.                                       TAG_DONE);
  3364.                 }
  3365.  
  3366.                 /*
  3367.                  *        Now check if the horizontal position of the
  3368.                  *        slider has changed.
  3369.                  */
  3370.                 if (dxwidth) {
  3371.                     int newwidth = CurrentFields[FBoxSelected].width + dxwidth;
  3372.  
  3373.                     if (newwidth < 1)                newwidth = 1;
  3374.                     if (newwidth > MAX_FIELD_LEN)    newwidth = MAX_FIELD_LEN;
  3375.                     if (FBoxSelected != FBOX_NOSELECT) {
  3376.                         if (newwidth != CurrentFields[FBoxSelected].width) {
  3377.                             GT_SetGadgetAttrs(Gadget[GID_FORMWIDTH],
  3378.                                               FormWindow,  NULL,
  3379.                                               GTSL_Level,  newwidth,
  3380.                                               TAG_DONE);
  3381.                             CurrentFields[FBoxSelected].width = newwidth;
  3382.                             ShowFormatLine(FBoxSelected, FORMAT_SELECTED);
  3383.                             InstallNewFormat(NEW_LISTVIEW);
  3384.                         }
  3385.                     }
  3386.                 }
  3387. done_keys:
  3388.                 break;
  3389.             }
  3390.         }
  3391.         GT_ReplyIMsg(imsg);
  3392.     }
  3393.     if (doneform != SEL_NONE) {
  3394.         CloseFormatWindow();
  3395.         if (doneform == SEL_CANCEL) {
  3396.             strcpy(BufFormat, FormatSaveFormat);
  3397.             InstallNewFormat(NEW_STRING);
  3398.         }
  3399.     }
  3400. }
  3401.  
  3402. /*
  3403.  *        -----------------------------------------------------------------------
  3404.  *        Now our BOB/GEL routines for the drag-and-drop format editor.
  3405.  *        These should really be in their own module, but they're being
  3406.  *        put here for now for convenience.
  3407.  *        -----------------------------------------------------------------------
  3408.  */
  3409.  
  3410. /*
  3411.  *        InitGel(rastport, width, height, transp)
  3412.  *
  3413.  *        This function does all the initialisation necessary to allow us
  3414.  *        to use a single BOB in the given rastport. A new bitmap is allocated
  3415.  *        of dimensions width x height into which data can be rendered.
  3416.  *
  3417.  *        If successful, this function returns a pointer to a MyGel structure
  3418.  *        which contains, among other things, the rastport and bob structure
  3419.  *        you will use when calling system routines to manipulate the bob.
  3420.  *
  3421.  *        Note that the bob must be removed from the Gel list before rendering
  3422.  *        into it.
  3423.  *
  3424.  *        If transp is true, then the BOB will be transparent on colour zero.
  3425.  *        In this case, you must call InitMasks(mygel->vsprite) whenever
  3426.  *        you make a change to the image, to recalculate the mask.
  3427.  */
  3428. MyGel *CreateBob(struct RastPort *rport, int width, int height, int transp)
  3429. {
  3430.     struct GelsInfo *gInfo;
  3431.     struct Bob        *bob;
  3432.     struct VSprite    *vsprite;
  3433.     MyGel            *mygel;
  3434.     ULONG            linesize;
  3435.     ULONG            planesize;
  3436.     ULONG            imagesize;
  3437.     ULONG            chipsize;
  3438.     UBYTE             *chipdata;
  3439.     int                wordwidth;
  3440.     int                depth;
  3441.     int                i;
  3442.  
  3443.     wordwidth    = (width + 15) >> 4;
  3444.     depth        = rport->BitMap->Depth;
  3445.  
  3446.     mygel = (MyGel *)AllocMem(sizeof(MyGel), MEMF_CLEAR);
  3447.     if (!mygel)
  3448.         return (NULL);
  3449.         
  3450.     mygel->mainrast        = rport;
  3451.     gInfo                = &mygel->gelinfo;
  3452.     gInfo->nextLine        = mygel->nextline;
  3453.     gInfo->lastColor    = mygel->lastcolor;
  3454.     gInfo->collHandler    = &mygel->colltable;
  3455.     gInfo->sprRsrvd        = 0x03;
  3456.  
  3457.     /*
  3458.      *        Set left-most and top-most to 1 to better keep items
  3459.      *        inside the display boundaries.
  3460.      */
  3461.     gInfo->leftmost   = 1;
  3462.     gInfo->topmost      = 1;
  3463.     gInfo->rightmost  = (rport->BitMap->BytesPerRow << 3) - 1;
  3464.     gInfo->bottommost = rport->BitMap->Rows - 1;
  3465.     rport->GelsInfo      = gInfo;
  3466.     InitGels(&mygel->vshead, &mygel->vstail, gInfo);
  3467.  
  3468.     /*
  3469.      *        Now allocate a new BOB to be linked into this structure.
  3470.      *        We also allocate a bitmap associated with the bob, and
  3471.      *        give it its own RastPort so that we can render into it.
  3472.      */
  3473.     linesize    = sizeof(WORD)  * wordwidth;
  3474.     planesize    = linesize      * height;
  3475.     imagesize    = planesize        * depth;
  3476.     chipsize    = imagesize*2 + linesize + planesize;
  3477.     bob            = &mygel->bob;
  3478.     vsprite        = &mygel->bobvsprite;
  3479.  
  3480.     if (!(chipdata = AllocMem(chipsize, MEMF_CHIP | MEMF_CLEAR))) {
  3481.         rport->GelsInfo = NULL;
  3482.         FreeMem(mygel, sizeof(MyGel));
  3483.         return (NULL);
  3484.     }
  3485.     mygel->chipdata        = (void *)(chipdata);
  3486.     mygel->chipsize        = chipsize;
  3487.  
  3488.     mygel->planedata    = (void *)(chipdata);
  3489.     bob->SaveBuffer        = (void *)(chipdata + imagesize);
  3490.     vsprite->BorderLine = (void *)(chipdata + imagesize*2);
  3491.     vsprite->CollMask    = (void *)(chipdata + imagesize*2 + linesize);
  3492.  
  3493.     vsprite->Y            = -9999;
  3494.     vsprite->X            = -9999;
  3495.     vsprite->Flags      = SAVEBACK | (transp ? OVERLAY : 0);
  3496.     vsprite->Width      = wordwidth;
  3497.     vsprite->Depth      = depth;
  3498.     vsprite->Height     = height;
  3499.     vsprite->MeMask     = 0;
  3500.     vsprite->HitMask    = 0;
  3501.     vsprite->ImageData  = (void *)mygel->planedata;
  3502.     vsprite->SprColors  = NULL;
  3503.     vsprite->PlanePick  = -1;
  3504.     vsprite->PlaneOnOff = 0x00;
  3505.     InitMasks(vsprite);
  3506.  
  3507.     vsprite->VSBob      = bob;
  3508.     bob->BobVSprite     = vsprite;
  3509.     bob->ImageShadow    = vsprite->CollMask;
  3510.     bob->Flags          = 0;
  3511.     bob->Before         = NULL;
  3512.     bob->After          = NULL;
  3513.     bob->BobComp        = NULL;
  3514.     bob->DBuffer        = NULL;
  3515.  
  3516.     /*
  3517.      *        Now setup the Rastport and Bitmap so we can render into the BOB
  3518.      */
  3519.     InitRastPort(&mygel->rastport);
  3520.     InitBitMap(&mygel->bitmap, depth, width, height);
  3521.     mygel->rastport.BitMap = &mygel->bitmap;
  3522.  
  3523.     for (i = 0; i < depth; i++)
  3524.         mygel->bitmap.Planes[i] = mygel->planedata + i * planesize;
  3525.  
  3526.     return (mygel);
  3527. }
  3528.  
  3529. /*
  3530.  *        FreeBob(mygel)
  3531.  *
  3532.  *        Frees the bob allocated earlier, along with all other associated info 
  3533.  *        Also removes all GELs from the system rastport.
  3534.  */
  3535. void FreeBob(MyGel *mygel)
  3536. {
  3537.     mygel->mainrast->GelsInfo = NULL;
  3538.     FreeMem(mygel->chipdata, mygel->chipsize);
  3539.     FreeMem(mygel, sizeof(MyGel));
  3540. }
  3541.  
  3542. /*
  3543.  *        PickupBob(hit, x, y)
  3544.  *
  3545.  *        Picks up the line and copies it into our bob's bitmap, then adds
  3546.  *        the bob to the screen at the current mouse location so the
  3547.  *        user can drag it around.
  3548.  *
  3549.  *        If the hit is correct, we can ignore Y since the field being
  3550.  *        dragged is in the right box and we already know which line.
  3551.  *        Otherwise, Y is a pixel co-ordinate that we use to calculate
  3552.  *        the line of the box that's being chosen.
  3553.  *
  3554.  *        If hit is FBOX_SELECTLEFT, then we need to calculate which line
  3555.  *        we are dealing with.
  3556.  *
  3557.  *        We also record the start line we use.
  3558.  *
  3559.  *        Returns true for success, false if we didn't have a hit after all.
  3560.  */
  3561. int PickupBob(int hit, int x, int y)
  3562. {
  3563.     struct RastPort *rport    = FormWindow->RPort;
  3564.     struct RastPort *bobrport = &TextBob->rastport;
  3565.     char viewbuf[50];
  3566.     int line;
  3567.     int box;
  3568.     int xpos;
  3569.     int ypos;
  3570.     int len;
  3571.  
  3572.     if (hit == FBOX_NOSELECT) {
  3573.         return (FALSE);
  3574.     } else if (hit == FBOX_SELECTLEFT) {
  3575.         box  = FORMAT_LEFTBOX;
  3576.         line = (y - FBoxA_Top - 2);
  3577.         if (line < FBoxSpacing)
  3578.             line = 0;
  3579.         else
  3580.             line /= FBoxSpacing;
  3581.         if (line >= FBoxA_CurLines)
  3582.             return (FALSE);
  3583.     } else {
  3584.         /* Right box */
  3585.         box  = FORMAT_RIGHTBOX;
  3586.         line = hit;
  3587.         if (line >= FBoxB_CurLines)
  3588.             return (FALSE);
  3589.     }
  3590.  
  3591.     /*
  3592.      *        Okay, got a definite hit so go ahead and start the drag
  3593.      */
  3594.     FormatDragBox    = box;
  3595.     FormatDragLine    = line;
  3596.     
  3597.     SetRast(bobrport, 0);                /* Erase rast bitmap     */
  3598.     SetAPen(bobrport, 2);                /* White foreground        */
  3599.     SetBPen(bobrport, 1);                /* Black background        */
  3600.     SetDrMd(bobrport, JAM2);            /* Solid text            */
  3601.     SetFont(bobrport, FormBufFont);
  3602.  
  3603.     if (box == FORMAT_LEFTBOX) {
  3604.         FieldInit *fi = &FieldTypes[AvailableFields[line].type];
  3605.  
  3606.         mysprintf(viewbuf, FBoxA_FormString, MSG(fi->titlemsgid), fi->idchar);
  3607.         len  = FBoxA_NumChars;
  3608.         xpos = FBoxA_Left + 2;
  3609.         ypos = FBoxA_Top  + 2 + line * FBoxSpacing;
  3610.     } else {
  3611.         FieldInit *fi = &FieldTypes[CurrentFields[line].type];
  3612.  
  3613.         mysprintf(viewbuf, FBoxB_FormString, MSG(fi->titlemsgid),
  3614.                            CurrentFields[line].width, fi->idchar);
  3615.         len  = FBoxB_NumChars;
  3616.         xpos = FBoxB_Left + 2;
  3617.         ypos = FBoxB_Top  + 2 + line * FBoxSpacing;
  3618.     }
  3619.     TextBob->bob.BobVSprite->X = xpos;
  3620.     TextBob->bob.BobVSprite->Y = ypos;
  3621.     FBoxDeltaX = xpos - x;
  3622.     FBoxDeltaY = ypos - y;
  3623.  
  3624.     Move(bobrport, 0, FormBufFont->tf_Baseline+1);
  3625.     Text(bobrport, viewbuf, len);
  3626.  
  3627.     /*
  3628.      *        Now draw highlight above and below the text
  3629.      */
  3630.     SetAPen(bobrport, 1);
  3631.     Move(bobrport, 0, 0);
  3632.     Draw(bobrport, len * FormBufFont->tf_XSize - 1, 0);
  3633.     Move(bobrport, 0, FormBufFont->tf_YSize + 1);
  3634.     Draw(bobrport, len * FormBufFont->tf_XSize - 1, FormBufFont->tf_YSize + 1);
  3635.  
  3636.     InitMasks(TextBob->bob.BobVSprite);
  3637.     SortGList(rport);
  3638.     DrawGList(rport, ViewPortAddress(FormWindow));
  3639.     return (1);
  3640. }
  3641.  
  3642. /*
  3643.  *        DropBob()
  3644.  *
  3645.  *        Releases the current bob at the target, and updates the two
  3646.  *        lists/displays accordingly.
  3647.  */
  3648. void DropBob(void)
  3649. {
  3650.     EditEvent savedev;
  3651.     EditEvent *ee;
  3652.     int destpos;
  3653.     int seltype;
  3654.  
  3655.     destpos = FBoxDragSelect;            /* Save destination drop selection    */
  3656.     UpdateBob(0, -9999);                /* Kill any highlighted region        */
  3657.  
  3658.     /*
  3659.      *        Now re-arrange the edit lists to reflect the new position of
  3660.      *        the dragged field. There are three cases to consider:
  3661.      *
  3662.      *            Left box    -> Right box
  3663.      *            Right box    -> Right box
  3664.      *            Right box    -> Left box
  3665.      */
  3666.     if (destpos == FBOX_NOSELECT)
  3667.         return;
  3668.     
  3669.     ShowFormatLine(FBoxSelected, FORMAT_UNSELECTED);
  3670.     if (FBoxSelected >= 0 && FBoxSelected < EF_COUNT)
  3671.         seltype = CurrentFields[FBoxSelected].type;
  3672.     else
  3673.         seltype = -1;
  3674.  
  3675.     /*
  3676.      *        First, delete item from its current list
  3677.      */
  3678.     if (FormatDragBox == FORMAT_LEFTBOX) {
  3679.         /*
  3680.          *        Deleting from left box
  3681.          */
  3682.         ee        = &AvailableFields[FormatDragLine];
  3683.         savedev.type  = ee->type;
  3684.         savedev.width = FieldTypes[ee->type].defwidth;
  3685.  
  3686.         while (ee->type != END_EDITLIST) {
  3687.             ee[0] = ee[1];
  3688.             ee++;
  3689.         }
  3690.         FBoxA_CurLines--;
  3691.         seltype = savedev.type;    /* New selection is item we just dragged */
  3692.     } else {
  3693.         /*
  3694.          *        Deleting from right box. If the drop position is after
  3695.          *        the point where we're deleting, we adjust it to reflect
  3696.          *        the deleted line.
  3697.          */
  3698.  
  3699.         if (destpos > FormatDragLine && destpos <= EF_COUNT)
  3700.             destpos--;
  3701.  
  3702.         ee        = &CurrentFields[FormatDragLine];
  3703.         savedev = *ee;
  3704.         while (ee->type != END_EDITLIST) {
  3705.             ee[0] = ee[1];
  3706.             ee++;
  3707.         }
  3708.         FBoxB_CurLines--;
  3709.     }
  3710.     /*
  3711.      *        Now add the item (savedev) to the new list in the appropriate
  3712.      *        place
  3713.      */
  3714.     if (destpos == FBOX_SELECTLEFT) {
  3715.         /*
  3716.          *        Search the existing left box list looking for the best place
  3717.          *        to insert the item -- we do this in strict alphabetical
  3718.          *        order (based on the % identifer)
  3719.          */
  3720.         int newid = FieldTypes[savedev.type].idchar;
  3721.         EditEvent tempev;
  3722.  
  3723.         for (ee = &AvailableFields[0]; ee->type != END_EDITLIST; ee++)
  3724.             if (FieldTypes[ee->type].idchar > newid)
  3725.                 break;
  3726.  
  3727.         do {
  3728.             tempev    = *ee;
  3729.             *ee     = savedev;
  3730.             savedev    = tempev;
  3731.             ee++;
  3732.         } while (ee[-1].type != END_EDITLIST);
  3733.         FBoxA_CurLines++;
  3734.     } else {
  3735.         /* 
  3736.          *        Adding line to the right box. Simply insert it at the
  3737.          *        specified location.
  3738.          */
  3739.         EditEvent tempev;
  3740.  
  3741.         ee = &CurrentFields[destpos];
  3742.         do {
  3743.             tempev    = *ee;
  3744.             *ee     = savedev;
  3745.             savedev    = tempev;
  3746.             ee++;
  3747.         } while (ee[-1].type != END_EDITLIST);
  3748.         FBoxB_CurLines++;
  3749.     }
  3750.     /*
  3751.      *        Now search our right box list to see can we match the item
  3752.      *        that was currently highlighted when we entered this routine.
  3753.      */
  3754.     FBoxSelected = 0;
  3755.     for (ee = &CurrentFields[0]; ee->type != END_EDITLIST; ee++) {
  3756.         if (ee->type == seltype)
  3757.             break;
  3758.         FBoxSelected++;
  3759.     }
  3760.     if (ee->type == END_EDITLIST) {
  3761.         FBoxSelected = FBOX_NOSELECT;
  3762.         GT_SetGadgetAttrs(Gadget[GID_FORMWIDTH], FormWindow,  NULL,
  3763.                           GA_Disabled, TRUE,
  3764.                           TAG_DONE);
  3765.     } else {
  3766.         GT_SetGadgetAttrs(Gadget[GID_FORMWIDTH], FormWindow,  NULL,
  3767.                           GA_Disabled, FALSE,
  3768.                           GTSL_Level,  ee->width,
  3769.                           TAG_DONE);
  3770.     }
  3771.  
  3772.     /*
  3773.      *        Now, finally, update our window to show the new arrangement.
  3774.      */
  3775.     RedrawFormatWindow();
  3776. }
  3777.  
  3778. /*
  3779.  *        UpdateBob(x, y)
  3780.  *
  3781.  *        Updates the current position of the bob on the screen, and
  3782.  *        draws any highlights etc. that are deemed necessary.
  3783.  */
  3784. void UpdateBob(int x, int y)
  3785. {
  3786.     int bfonty = FormBufFont->tf_YSize;
  3787.     int pos;
  3788.  
  3789.     /*
  3790.      *        Now see if we are overlapping any of the drop regions, and if
  3791.      *        so, highlight the region appropriately.
  3792.      *
  3793.      *        When dragging into the left box, we highlight the entire box
  3794.      *        since the order of items is pre-determined and it doesn't
  3795.      *        make any sense to drop a field into one particular place.
  3796.      *
  3797.      *        When dragging into the right box, we highlight a line in
  3798.      *        between two other lines, which shows where the item will
  3799.      *        be inserted.
  3800.      *
  3801.      *        For neatness, we don't show highlighting which would have
  3802.      *        no effect on the current settings (i.e. moving a field to
  3803.      *        the same position it's already in).
  3804.      */
  3805.     pos = FBOX_NOSELECT;
  3806.     if (x >= FBoxA_Left && x <= (FBoxA_Left + FBoxA_Width  - 1) &&
  3807.         y >= FBoxA_Top  && y <= (FBoxA_Top  + FBoxA_Height - 1) &&
  3808.         FormatDragBox != FORMAT_LEFTBOX) {
  3809.         /*
  3810.          *        Got a hit in left-hand box
  3811.          */
  3812.         pos = FBOX_SELECTLEFT;
  3813.     } else if (x >= FBoxB_Left && x <= (FBoxB_Left + FBoxB_Width - 1) &&
  3814.                y >= (FBoxB_Top - 10) && y <= (FBoxB_Top + FBoxB_Height + 10)) {
  3815.         /*
  3816.          *        Got a hit in the right-hand box, so now calculate which line
  3817.          */
  3818.         pos = (y - FBoxB_Top - 2 + bfonty/2) / FBoxSpacing;
  3819.  
  3820.         if (pos < 0)                pos = 0;
  3821.         if (pos > FBoxB_CurLines)    pos = FBoxB_CurLines;
  3822.         if (FormatDragBox == FORMAT_RIGHTBOX &&
  3823.                         (pos == FormatDragLine || pos == (FormatDragLine+1))) {
  3824.             pos = FBOX_NOSELECT;    /* Don't highlight line we dragged from */
  3825.         }
  3826.     }
  3827.  
  3828.     if (pos != FBoxDragSelect) {
  3829.         /*
  3830.          *        Currently selected item has changed, so erase current one,
  3831.          *        then draw new one. We also refresh the currently selected
  3832.          *        line, in case it got trashed by the highlighting.
  3833.          *
  3834.          *        Note that we must first move the bob off-screen while we
  3835.          *        render the changes, otherwise it gets confused and tends
  3836.          *        to obscure the output.
  3837.          */
  3838.         TextBob->bob.BobVSprite->X = 0;
  3839.         TextBob->bob.BobVSprite->Y = -9999;
  3840.         SortGList(FormWindow->RPort);
  3841.         DrawGList(FormWindow->RPort, ViewPortAddress(FormWindow));
  3842.         ShowDragSelect(FBoxDragSelect, FORMAT_UNSELECTED);
  3843.         ShowFormatLine(FBoxSelected, FORMAT_SELECTED);
  3844.         ShowDragSelect(pos, FORMAT_SELECTED);
  3845.         FBoxDragSelect = pos;
  3846.     }
  3847.  
  3848.     TextBob->bob.BobVSprite->X = x + FBoxDeltaX;
  3849.     TextBob->bob.BobVSprite->Y = y + FBoxDeltaY;
  3850.     SortGList(FormWindow->RPort);
  3851.     DrawGList(FormWindow->RPort, ViewPortAddress(FormWindow));
  3852. }
  3853.